【问题标题】:R conditionally matching date-time from one dataframe to closest date-time field in second dataframeR有条件地将日期时间从一个数据帧匹配到第二个数据帧中最近的日期时间字段
【发布时间】:2015-05-18 03:19:03
【问题描述】:

我有两个数据框,df.events 和 df.activ。

df.activ 具有非常精细的分钟级数据,并且比具有约 100,000 条记录的 df.events 多一个数量级的记录(1,000,000+),也是分钟级粒度。这两个数据帧有两个公共字段,日期时间和地理。两个 DateTime 列都采用 as.POSIXlt, %Y-%m-%d %H:%M:%S 格式。

df.activ <- read.table(text=
                          '"DateTime","Geo","Bin1","Bin2"
                        2014-07-01 00:11:00,NA,0,0
                        2014-07-01 00:11:00,NA,0,0
                        2014-07-01 00:11:00,NA,0,0
                        2014-07-01 00:11:00,NA,0,0
                        2014-07-01 00:11:00,NA,0,0
                        2014-07-01 00:12:00,NA,0,0
                        2014-07-01 00:12:00,510,0,1
                        2014-07-01 00:12:00,NA,0,0
                        2014-07-01 00:12:00,NA,0,0
                        2014-07-01 00:12:00,NA,0,0
                        2014-07-01 00:12:00,NA,0,0
                        2014-07-01 00:12:00,NA,0,0
                        2014-07-01 00:13:00,618,1,1
                        2014-07-01 00:13:00,510,0,1
                        2014-07-01 00:13:00,NA,0,0
                        2014-07-01 00:13:00,NA,0,0
                        2014-07-01 00:13:00,NA,0,0
                        2014-07-01 00:13:00,NA,0,0
                        2014-07-01 00:13:00,NA,0,0
                        2014-07-01 00:13:00,NA,0,0
                        2014-07-01 00:13:00,NA,0,0',header=TRUE,sep=",")

df.events <- read.table(text=
                          '"Units","Geo","DateTime"
                        225,999,2014-07-01 00:09:00
                        40,510,2014-07-01 00:12:00
                        5,999,2014-07-01 00:28:00
                        115,999,2014-07-01 00:44:00
                        0,999,2014-07-01 00:47:00',header=TRUE,sep=",")

如果同一行(在 df.events 中)的 Geo 字段值为 999,我的目标是将 df.activ 合并到 df.events 中最近的 DateTime。

如果 df.event 的 Geo 不是 999,那么我只想在 Geo 字段匹配的情况下合并 df.event(例如,在提供的数据框中 Geo = 510 的情况)。

我知道 for 循环不是解决 R 中问题的正确方法,但从概念上讲,我希望通过循环 df.activ 的 DateTime 字段并以最接近的方式记录如果 Geo 字段为 999 或与 df.activ 中的 Geo 字段匹配,则来自 df.events 的 DateTime。

下面的数据框是我所追求的:

df.idealresults <- read.table(text=
                              'DateTime,Geo,Bin1,Bin2,events.DateTime,events.Units,Events.Geo
                              7/1/2014 0:11,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:11,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:11,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:11,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:11,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:12,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:12,510,0,1,7/1/2014 0:12,40,510
                              7/1/2014 0:12,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:12,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:12,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:12,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:12,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:13,618,1,1,7/1/2014 0:09,225,999
                              7/1/2014 0:13,510,0,1,7/1/2014 0:12,40,510
                              7/1/2014 0:13,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:13,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:13,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:13,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:13,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:13,NA,0,0,7/1/2014 0:09,225,999
                              7/1/2014 0:13,NA,0,0,7/1/2014 0:09,225,999',header=TRUE,sep=',')

到目前为止,我已经能够将 df.activ 合并到 df.events 中最近的 DateTime。我使用受this SO post 答案后半部分启发的基于 na.locf 的方法完成了此操作。我一直在努力尝试将地理匹配逻辑合并到这种方法中; na.locf 的性质使得这项工作难以正常进行,因为它依赖于在合并步骤之前绑定的向量到向量 NA。

【问题讨论】:

  • 我不明白为什么 Geo==510 在 df.idealresults 中出现两次
  • 你能回答你到目前为止所做的事情吗?
  • @ExperimenteR 假设一个错字,因为在数据中它应该是第 7 行的 507。
  • 是的,那是我的错误。我现在已经纠正了。为可能造成的混乱道歉。
  • @leaRningR909 我看到多米尼克已经给了你一个很好的答案。以防万一,如果您想提高性能,您可能需要考虑从data.table 包或inner_join 来自dplyr 包的滚动连接。

标签: r datetime merge dataframe time-series


【解决方案1】:

有时很难避免循环,尤其是当您遇到类似的情况时。有时我们最终会花费很多精力来避免它们,而它们可能是我们能做的最好的,或者在性能和/或可读性方面并不太落后。话虽如此,这可以解决问题:

df.activ$DateTime <- as.POSIXct(df.activ$DateTime)
df.events$DateTime <- as.POSIXct(df.events$DateTime)

results <- df.activ
results$events.Units=NA
results$events.Geo=NA
results$events.Datetime=NA

for(i in seq_len(nrow(df.activ))) {
  diffs <- order(abs(df.activ$DateTime[i] - df.events$DateTime))
  for(j in seq_along(diffs)) {
    if(df.events$Geo[diffs[j]] == 999) {
      results[i, 5:7] <- df.events[diffs[j],]
      break
    } else if(isTRUE(df.events$Geo[diffs[j]] == df.activ$Geo[i])) {
      results[i, 5:7] <- df.events[diffs[j],]
      break
    }
  }
}

results$events.DateTime <- as.POSIXct(results$events.Datetime,origin = "1970-01-01")

results
              DateTime Geo Bin1 Bin2 events.Units events.Geo events.Datetime     events.DateTime
1  2014-07-01 00:11:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
2  2014-07-01 00:11:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
3  2014-07-01 00:11:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
4  2014-07-01 00:11:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
5  2014-07-01 00:11:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
6  2014-07-01 00:12:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
7  2014-07-01 00:12:00 510    0    1           40        510      1404187920 2014-07-01 00:12:00
8  2014-07-01 00:12:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
9  2014-07-01 00:12:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
10 2014-07-01 00:12:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
11 2014-07-01 00:12:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
12 2014-07-01 00:12:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
13 2014-07-01 00:13:00 618    1    1          225        999      1404187740 2014-07-01 00:09:00
14 2014-07-01 00:13:00 510    0    1           40        510      1404187920 2014-07-01 00:12:00
15 2014-07-01 00:13:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
16 2014-07-01 00:13:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
17 2014-07-01 00:13:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
18 2014-07-01 00:13:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
19 2014-07-01 00:13:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
20 2014-07-01 00:13:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00
21 2014-07-01 00:13:00  NA    0    0          225        999      1404187740 2014-07-01 00:09:00

【讨论】:

  • 谢谢多米尼克。这很好用。只是一个快速的后续问题:如果我要将此代码扩展到具有数百万条记录的数据帧,在这种情况下避免循环是 R 的最佳实践吗?我将尝试修改 [this post] (stackoverflow.com/questions/17321886/…) 中的 function + sapply 方法,并使用循环方法与 system.time 进行正面交锋。
  • 不客气!对于您的问题,很难找到明确的答案。关于这个话题有很多已经说过并且仍在被谈论的事情。我不习惯使用大型数据库,所以通常我对循环很好。我不认为一百万行会成为问题,除非你有一台低内存的机器(即使那样,问题更多的是速度而不是内存)。但我很想知道你的情况如何;如果您确实提出了替代解决方案,请随时向我们提供您的结果。
【解决方案2】:

我在工作,这似乎相对解决了,所以我会简短。您也可以进行完整的外部合并,然后简单地获取日期的差异。使用 distinct 按日期差的绝对值排序。

这可能是进行合并的算法上最快的方法,但需要比循环更多的 RAM(您的完整合并将有 n1*n2 个观察值)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 2013-06-23
    • 2020-09-20
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多