【问题标题】:Find first row that meets condition after each row's date, by group按组查找每行日期后满足条件的第一行
【发布时间】:2020-06-27 20:39:05
【问题描述】:

我有一个带有 5 个变量的 data.frameday(日期,格式:“YYYY-MM-DD”),小时(POSIXct,格式:“YYYY -MM-DD hh:mm:ss")、group(字符)、measure_start(数字)和measure_end(数字)。 p>

df <- structure(list(
  day = structure(c(18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116, 18116), class = "Date"), 
  hour = structure(c(1565275500, 1565276400, 1565277300, 1565278200, 1565279100, 1565280000, 1565280900, 1565281800, 1565282700, 1565275500, 1565276400, 1565277300, 1565278200, 1565279100, 1565280000, 1565280900, 1565281800, 1565282700), class = c("POSIXct", "POSIXt"), tzone = ""), 
  group = c("GROUP1", "GROUP1", "GROUP1", "GROUP1", "GROUP1", "GROUP1", "GROUP1", "GROUP1", "GROUP1", "GROUP2", "GROUP2", "GROUP2", "GROUP2", "GROUP2", "GROUP2", "GROUP2", "GROUP2", "GROUP2"), 
  measure_start = c(2, 3, 3, 2, 4, 5, 7, 8, 7, 15, 16, 32, 20, 21, 40, 15, 13, 22), 
  measure_end = c(3, 3, 3, 5, 4, 7, 7, 8, 7, 16, 15, 31, 20, 21, 42, 15, 13, 26)),
  row.names = c(NA, -18L), class = "data.frame")

对于data.frame 的每一行“i”,我想获取满足条件“measure_end >= 2 * measure_start_i”的第一行;但仅适用于一天中大于或等于“i​​”行的小时的时间,并且按“i”行的相同 daygroup 分组.

换句话说,对于每个观察 [day_i, hour_i, group_i, measure_start_i, measure_end_i] 我想得到:which.min (measure_end >= 2 * measure_start_i | (day == day_i) & (group == group_i) & (hour >= hour_i))。

例如,对于上面的示例,预期的输出应该是:

          day                hour  group measure_start measure_end      row_with_me_2x_current_ms
1  2019-08-08 2019-08-08 11:45:00 GROUP1             2           3                              4
2  2019-08-08 2019-08-08 12:00:00 GROUP1             3           3                              6
3  2019-08-08 2019-08-08 12:15:00 GROUP1             3           3                              6
4  2019-08-08 2019-08-08 12:30:00 GROUP1             2           5                              4
5  2019-08-08 2019-08-08 12:45:00 GROUP1             4           4                              8
6  2019-08-08 2019-08-08 13:00:00 GROUP1             5           7                             NA
7  2019-08-08 2019-08-08 13:15:00 GROUP1             7           7                             NA
8  2019-08-08 2019-08-08 13:30:00 GROUP1             8           8                             NA
9  2019-08-08 2019-08-08 13:45:00 GROUP1             7           7                             NA
10 2019-08-08 2019-08-08 11:45:00 GROUP2            15          16                             12
11 2019-08-08 2019-08-08 12:00:00 GROUP2            16          15                             15
12 2019-08-08 2019-08-08 12:15:00 GROUP2            32          31                             NA
13 2019-08-08 2019-08-08 12:30:00 GROUP2            20          20                             15
14 2019-08-08 2019-08-08 12:45:00 GROUP2            21          21                             15
15 2019-08-08 2019-08-08 13:00:00 GROUP2            40          42                             NA
16 2019-08-08 2019-08-08 13:15:00 GROUP2            15          15                             NA
17 2019-08-08 2019-08-08 13:30:00 GROUP2            13          13                             18
18 2019-08-08 2019-08-08 13:45:00 GROUP2            22          26                             NA

我的data.frame 非常大,所以我猜data.table 方法可能效果最好。不过,我仍然不太熟悉data.table 语法。我在下面的尝试没有多大帮助:

dt = data.table(df)
dt[,row_with_me_2x_current_ms:= which.min(dt[,measure_end] / measure_start >= 2) ,by=.(day,group)]

【问题讨论】:

  • 你能显示预期的输出吗
  • 预期的输出如上所示。谢谢!

标签: r data.table


【解决方案1】:

这是另一个使用来自data.table 的非等连接的选项:

setDT(df)[, c("rn", "twice") := .(.I, 2 * measure_start)]

df[, row_with_me_2x_current_ms := 
    df[.SD, on=.(group, day, hour>=hour, measure_end>=twice), mult="first", rn]
]

【讨论】:

    【解决方案2】:

    如果我们想得到逻辑向量的第一个索引。我们可以对'day','group'进行分组,然后用lapply循环'measure_start'的序列,子集'measure_start'('mst')的值,除以'measure_end',得到索引第一行满足条件并赋值

    library(data.table) 
    dt[, row_with_me_2x_current_ms:= 
         unlist(lapply(seq_along(measure_start), function(i) {
            mst <- measure_start[i]
            i2 <- which((measure_end/mst) >=2)
            .I[i2[i2 >= i][1]]})),
       by = .(group, day)]
    dt
    #           day                hour  group measure_start measure_end row_with_me_2x_current_ms
    # 1: 2019-08-08 2019-08-08 09:45:00 GROUP1             2           3                         4
    # 2: 2019-08-08 2019-08-08 10:00:00 GROUP1             3           3                         6
    # 3: 2019-08-08 2019-08-08 10:15:00 GROUP1             3           3                         6
    # 4: 2019-08-08 2019-08-08 10:30:00 GROUP1             2           5                         4
    # 5: 2019-08-08 2019-08-08 10:45:00 GROUP1             4           4                         8
    # 6: 2019-08-08 2019-08-08 11:00:00 GROUP1             5           7                        NA
    # 7: 2019-08-08 2019-08-08 11:15:00 GROUP1             7           7                        NA
    # 8: 2019-08-08 2019-08-08 11:30:00 GROUP1             8           8                        NA
    # 9: 2019-08-08 2019-08-08 11:45:00 GROUP1             7           7                        NA
    #10: 2019-08-08 2019-08-08 09:45:00 GROUP2            15          16                        12
    #11: 2019-08-08 2019-08-08 10:00:00 GROUP2            16          15                        15
    #12: 2019-08-08 2019-08-08 10:15:00 GROUP2            32          31                        NA
    #13: 2019-08-08 2019-08-08 10:30:00 GROUP2            20          20                        15
    #14: 2019-08-08 2019-08-08 10:45:00 GROUP2            21          21                        15
    #15: 2019-08-08 2019-08-08 11:00:00 GROUP2            40          42                        NA
    #16: 2019-08-08 2019-08-08 11:15:00 GROUP2            15          15                        NA
    #17: 2019-08-08 2019-08-08 11:30:00 GROUP2            13          13                        18
    #18: 2019-08-08 2019-08-08 11:45:00 GROUP2            22          26                        NA
    

    【讨论】:

    • 感谢您的建议,但重要的是我们要找到满足 每个 行条件的第一个索引(而不仅仅是第一个)。请参阅上面的预期输出。
    • @pabc 可能是您的逻辑不正确或预期输出。我无法在预期输出列中复制这些值
    • 嗨@akrun。对不起,如果我的逻辑不清楚。输出列应返回行的第一个索引,分组在 (day, group) 下,“measure_end”列中的值至少是“measure_start”值的两倍。应该对每一行进行此计算。例如:对于第 1 行,我们有 measure_start == 2。所以返回的值应该是“4”,这是 measure_end >=2 的第一行。对于第 2 行,我们有 measure_start == 3,因此返回值应该是“6”,这是 measure_end >=3 的第一行;等等……
    • @pabc 我正在尝试这个逻辑。根据您的第一行代码(不包括此处的组)which((dt$measure_end[1]/dt$measure_start) &gt;=2)# integer(0)
    • @pabc 即 3/5 = 0.6 且不等于 >=2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-01
    • 2013-10-19
    • 1970-01-01
    • 1970-01-01
    • 2020-01-31
    相关资源
    最近更新 更多