【问题标题】:R: Subsetting subsets of a dataframe based on NROW of another factor in the same data.frameR:基于同一数据帧中另一个因素的 NROW 对数据帧的子集进行子集化
【发布时间】:2018-09-21 12:51:15
【问题描述】:

我在两个位置(参考 mast6 和 sonic_f)有 3 个方向(u、v 和 w)的风速读数,用于特定风 角度(例如 0º、5º 等)我已导入并绑定所有这些都放在一个 data.frame 中。

我想以成对的形式绘制数据,但参考桅杆在前 X 秒内没有记录。我需要将声波文件修剪为等效参考桅杆数据为每个角度和每个 u v 或 w 方向显示的第一个时间戳。

例如,每个位置的开始时间如下:

> aggregate(data=df,StartTime~MeasurementLocation+Angle,min)
         Location Angle StartTime
1     mast6_u      00    17602
2     mast6_v      00    17602
3     mast6_w      00    18602
4   sonic_f_u      00        2
5   sonic_f_v      00        2
6   sonic_f_w      00        2
7     mast6_u      05    13001
8     mast6_v      05    13001
9     mast6_w      05    13002
10  sonic_f_u      05        2
11  sonic_f_v      05        2
12  sonic_f_w      05        2

因此,例如,属于角度 00 的所有数据的开始时间必须是 18602。 编辑

所需的输出将是每个角度的单独文件,对于 Angle==00,sonic_f_u v 或 w 的长度与来自 mast_u v 或 w 的同一角度的最短数据集的长度相同。例如。对于角度 00,mast6_u v 和 w 都必须从 18602 开始,sonic_f_u v 和 w 也应该如此。

【问题讨论】:

  • 期望的输出是 Angle==00 的 mast6_u 的长度与 Angle==00 的 sonic_f_u 的长度相同。所以要做到这一点,我需要去掉 sonic_f_u 中的前 17601 个值
  • 请使用dput() 分享您的数据,以便其他人可以提供帮助。在此处查看更多信息How to make a great R reproducible example?
  • @Tong 我不知道如何制作数据,从概念上讲它很奇怪,但它是一个很好的 rbinded data.frame,包含很多两列数据。想象一下,这就像两个不同长度的 Excel 列,每个角度堆叠在一起。我最终手动拆分。
  • 不清楚您的预期输出,18602 是前 6 个条目的输出。接下来 6 个条目的输出是什么?你想要每个Anglemax 值吗?

标签: r dplyr


【解决方案1】:

在这方面很难击败 data.table...

library(data.table)
setDT(df)[ , start_time_max := max( StartTime ), by = Angle][StartTime >= start_time_max, ][, start_time_max := NULL][]

#    Num Location Angle StartTime
# 1:   3  mast6_w     0     18602
# 2:   9  mast6_w     5     13002

基准

microbenchmark::microbenchmark(
  data.table = setDT(df)[ , start_time_max := max( StartTime ), by = Angle][StartTime >= start_time_max, ][, start_time_max := NULL][],
  tidyverse = { left_join(df,
                          df %>%
                            group_by(Angle) %>%
                            summarise(max(StartTime)),
                          by = "Angle"
  ) %>%
      filter(StartTime == `max(StartTime)`) %>%
      select(-`max(StartTime)`) %>%
      arrange(Angle, Location) %>%
      unique()

    }, times = 100
)

# Unit: microseconds
#       expr      min       lq     mean   median       uq       max neval
# data.table  937.233 1050.057 1195.317 1196.169 1289.260  1808.488   100
# tidyverse  4694.900 4991.645 5409.146 5172.855 5341.563 24359.309   100

【讨论】:

  • 谢谢@Wimpel。我需要首先计算最小开始时间,然后执行 max(min(StartTime) 以确保所有文件同时开始。另一件事是 data.frame 中的时间不按顺序排列。例如我可能有 1 ,2,3,4,4,5,5,6,100,7,101,8,102 等。可以使用 data.tables 处理吗?
  • @HCAI data.table 可以处理很多事情。但我不完全理解您评论中的问题。我的答案适用于您的示例数据和所需的输出。如果您想检查我的答案是否适用于您的生产数据:只有一种方法可以找出答案!
  • 问题是我偶尔会重复测量每个位置。所以仅仅因为现在的值是同时开始的(因为你已经把剩下的都剪掉了),我仍然有不同长度的文件:aggregate(data=ds,Time~MeasurementLocation+Angle,NROW) MeasurementLocation Angle Time 1 mast6_u 0 15061 2 mast6_v 0 27061 3 mast6_w 0 15061
  • 我觉得这样就可以解决了:arrange(Angle, Location) %>%distinct(Time,.keep_all = TRUE)
【解决方案2】:

我不认为我完全理解您的用例,但这就是我的解释:对于每个角度,您希望找到最大开始时间并过滤桅杆和声波的所有风向的数据帧以有相同的开始时间。

在 tidyverse 中,您可以通过找到每个角度的最大开始时间并将其连接到原始数据框中来做到这一点。然后使用过滤器去除不匹配的开始时间:

left_join(df,
          df %>%
            group_by(Angle) %>%
            summarise(max(StartTime)),
          by = "Angle"
) %>%
  filter(StartTime == `max(StartTime)`) %>%
  select(-`max(StartTime)`) %>%
  arrange(Angle, Location) %>%
  unique()

# # A tibble: 2 x 4
#   Location Angle StartTime
#   <chr>    <int>     <int>
# 1 mast6_w      0     18602
# 2 mast6_w      5     13002

使用arrange() 对列进行排序以删除重复的行,使用unique() 去除重复项(如果行列不相同,您可能需要更健壮的东西。

【讨论】:

  • 嗨@Paul 谢谢你看起来棒极了。我注意到并非所有读数都是按顺序排列的,而且由于测量误差,有些读数是重复的。它可以包含在那个很棒的 dplyr 函数中吗?
  • 是的,请参阅 arrange()unique(),查看更新后的答案。
【解决方案3】:

假设我有:

> dat
     Num  Location Angle StartTime
1    1   mast6_u     0     17602
2    2   mast6_v     0     17602
3    3   mast6_w     0     18602
4    4 sonic_f_u     0         2
5    5 sonic_f_v     0         2
6    6 sonic_f_w     0         2
7    7   mast6_u     5     13001
8    8   mast6_v     5     13001
9    9   mast6_w     5     13002
10  10 sonic_f_u     5         2
11  11 sonic_f_v     5         2
12  12 sonic_f_w     5         2

要将所有0 角度转换为0 处的值mast6_w,您可以这样做:

for (angle in c(0,5))
{
   dat[which(dat$Angle==0),4] <- dat[which(dat$Location=="mast6_w" & dat$Angle==0),4]
}

这会将所有0 角度的第4 列值设置为0mast6_w 处的值。然后你会得到:

> dat
   Num  Location Angle StartTime
1    1   mast6_u     0     18602
2    2   mast6_v     0     18602
3    3   mast6_w     0     18602
4    4 sonic_f_u     0     18602
5    5 sonic_f_v     0     18602
6    6 sonic_f_w     0     18602
7    7   mast6_u     5     13001
8    8   mast6_v     5     13001
9    9   mast6_w     5     13002
10  10 sonic_f_u     5         2
11  11 sonic_f_v     5         2
12  12 sonic_f_w     5         2

对于其他人来说,这里的结构是:

structure(list(Num = 1:12, Location = c("mast6_u", "mast6_v", 
"mast6_w", "sonic_f_u", "sonic_f_v", "sonic_f_w", "mast6_u", 
"mast6_v", "mast6_w", "sonic_f_u", "sonic_f_v", "sonic_f_w"), 
    Angle = c(0L, 0L, 0L, 0L, 0L, 0L, 5L, 5L, 5L, 5L, 5L, 5L), 
    StartTime = c(17602L, 17602L, 18602L, 2L, 2L, 2L, 13001L, 
    13001L, 13002L, 2L, 2L, 2L)), class = "data.frame", row.names = c(NA, 
-12L))

【讨论】:

  • 感谢您的回答。我没有发现 for 循环对我的数据有任何作用。此外,mast6_w 可能不是每个角度的最短数据集(有时 mast6_u 或 mast6_v 存在故障)
  • 请注意,在我的示例中,我很仓促,角度不是文本:0 与“00”。这个例子中的 for 循环是不必要的,我把它留在里面的原因是因为对于每个角度你可能想做一些不同的事情,因为你说:“例如,属于角度 00 的所有数据的开始时间必须在18602。”
  • @Paul 的回答似乎已经进一步猜到了你在寻找什么。
猜你喜欢
  • 2020-07-07
  • 2021-10-16
  • 2018-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多