【问题标题】:Check if values are within a certain range of a separate dataframe检查值是否在单独数据框的特定范围内
【发布时间】:2018-05-29 19:44:33
【问题描述】:

我有以下两个数据框:

df <- data.frame(id = c("AED","AED","CFR","DRR","DRR","DRR","UN","PO"),
             dates = as.POSIXct(c("2018-05-17 09:52:00","2018-05-17 10:49:00","2018-05-17 10:38:00","2018-05-17 11:29:00","2018-05-17 12:12:00","2018-05-17 13:20:00","2018-05-17 14:28:00","2018-05-17 15:59:00")))

events <- data.frame(id = c("AED","CFR","DRR","DRR","UN"),
                 start = as.POSIXct(c("2018-05-17 10:00:00","2018-05-17 10:18:00","2018-05-17 11:18:00","2018-05-17 13:10:00","2018-05-17 14:18:00")),
                 end = as.POSIXct(c("2018-05-17 11:56:00","2018-05-17 12:23:00","2018-05-17 12:01:00","2018-05-17 14:18:00",NA)))

通过唯一 id,我想将 df 中的每个日期与 events 数据框中列出的各个日期范围进行比较(事件数据框的每一行都被认为是自己的时间范围),以便得到以下结果:

result <- data.frame(id = c("AED","AED","CFR","DRR","DRR","DRR","UN","PO"),
                 dates = c("2018-05-17 09:52:00","2018-05-17 10:49:00","2018-05-17 10:38:00","2018-05-17 11:29:00","2018-05-17 12:12:00","2018-05-17 13:20:00","2018-05-17 14:28:00","2018-05-17 15:59:00"),
                 inRange = c(FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE),
                 outsideRange = c(TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE))

如果来自 df 的 id 不在事件中,则为 inRange 和 outsideRange 返回 FALSE;如果 df 日期大于 event$start,但 events$end 为 NA,则 inRange 应为 TRUE

我希望将解决方案应用于至少 500,000 行的更大数据集。

【问题讨论】:

  • 你有这么多被放弃/未解决的问题。您可以接受这些问题的答案,以便对未来的用户有所帮助。

标签: r dataframe compare


【解决方案1】:

在基础 R 中:

df2 <- merge(df,events)
df2 <- within(df2, inRange <- dates > start & dates < end)
df2 <- aggregate(inRange ~ dates,df2,any)
#                 dates inRange
# 1 2018-05-17 09:52:00   FALSE
# 2 2018-05-17 09:56:00   FALSE
# 3 2018-05-17 10:38:00    TRUE
# 4 2018-05-17 11:29:00    TRUE
# 5 2018-05-17 12:12:00   FALSE
# 6 2018-05-17 13:20:00   FALSE
# 7 2018-05-17 14:28:00    TRUE
# 8 2018-05-17 15:59:00   FALSE

这里的第一个合并是笛卡尔积,如果您的数据很大,我们最好先在两边提取一天然后合并。

这意味着在上面的代码之前这样做:

df$year <- as.Date(df$dates)
events$year <- as.Date(events$start) # assuming start and end are always on same day

【讨论】:

    【解决方案2】:

    一种选择是使用non-equi 使用data.table 更新加入。在dates&gt;=startdates&lt;=end 上加入dfevents。将inRange 列设置为TRUE 以匹配记录。

    library(data.table)
    
    setDT(df)
    setDT(events)
    
    df[events, on=c("dates>=start", "dates<=end"), inRange := TRUE]
    df
    #                  dates inRange
    # 1: 2018-05-17 09:52:00      NA
    # 2: 2018-05-17 09:56:00      NA
    # 3: 2018-05-17 10:38:00    TRUE
    # 4: 2018-05-17 11:29:00    TRUE
    # 5: 2018-05-17 12:12:00      NA
    # 6: 2018-05-17 13:20:00      NA
    # 7: 2018-05-17 14:28:00    TRUE
    # 8: 2018-05-17 15:59:00      NA
    # 
    

    【讨论】:

      【解决方案3】:

      如果events不重叠,则对开始和结束坐标进行排序,并使用findInterval()确定奇数区间内的日期

      x = with(events, sort(c(start, end)))
      df$inRange = findInterval(df$dates, x) %% 2 == 1
      

      如果events确实重叠,则创建一个包含所有事件的向量,弄清楚如何将它们按顺序排列,然后这样做

      times <- with(events, c(start, end))
      o <- order(times)
      times <- times[o]
      

      创建一个event向量,当开始发生时为1,当发生结束时为-1,并将这些事件按顺序排列

      event <- rep(c(1, -1), each = nrow(events))[o]
      

      计算“覆盖率”,即当前有效的事件数。

      cvg <- cumsum(event)
      

      最后,创建一个更新的 events 数据框,其中开始和结束是从覆盖率为 1 且事件为“开始”事件的“开始”值派生的,结束也是如此

      times[ (event == 1 & cvg == 1) | (event == -1 & cvg == 0) ]
      

      并按照上述方法进行。

      把这些放在一起

      reduce_int <- function(start, end) {
          x <- c(start, end)
          o <- order(x)
          x <- x[o]
      
          event <- rep(c(1, -1), each = nrow(events))[o]
          cvg <- cumsum(event)
      
          x[ (event == 1 & cvg == 1) | (event == -1 & cvg == 0) ]
      }
      
      overlaps <- function(x, events) {
          vec <- reduce_int(event$start, event$end)
          findInterval(x, vec) %% 2 == 1
      }
      

      使用

      df$inRange <- overlaps(df$dates, events)
      

      【讨论】:

        猜你喜欢
        • 2022-11-15
        • 1970-01-01
        • 2012-09-27
        • 2021-04-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多