【问题标题】:Conditional join on multiple date ranges多个日期范围的条件连接
【发布时间】:2017-05-05 14:00:34
【问题描述】:

我有两个数据框:“探针”和“事件”。下面的代码将生成这些数据帧的可重现样本。 Probes.subset 是来自 Probes 的所有观测值的数据框,这些观测值与事件中的日期时间范围相交。 下面的代码将生成 6 个事件...实际上我有近 200 个离散事件。

目标:我需要将Events中的Event.name加入到基于Timestamp的Probes.subset中的每个对应观察中,以便每个观察都与正确的事件相关联。

have previously tried a FOR loop 但这非常慢并且由于我的数据超过 180,000 行而无法完成。我有一种感觉,这可以通过编写一个函数并使用类似 apply 的东西来解决,但我是 R 函数的新手,我创建的函数都没有。

library(dplyr)

# Generate Probes data
start <- as.POSIXct("01/06/2016 01:00", format = "%d/%m/%Y %H:%M")
end <- start + as.difftime(1, units = "days")

Timestamp <- seq(from = start, to = end, by = "10 mins")
Value <- round(runif(145) * 100, 2)

Probes <- data.frame(Timestamp, Value)

# Generate Events data
Event.name <- seq(1, 6)

Event.start <- as.POSIXct(c("01/06/2016 01:20", "01/06/2016 05:00",
                            "01/06/2016 06:30", "01/06/2016 12:00",
                            "01/06/2016 17:40", "01/06/2016 19:20"),
                          format = "%d/%m/%Y %H:%M")

Event.end <- as.POSIXct(c("01/06/2016 02:00", "01/06/2016 05:30",
                            "01/06/2016 07:20", "01/06/2016 14:00",
                            "01/06/2016 18:10", "01/06/2016 21:40"),
                          format = "%d/%m/%Y %H:%M")

Events <- data.frame(Event.name, Event.start, Event.end)

# Subset probes data to fall within Events bounds
Probes.subset <- Probes %>%
  mutate(InRange = Timestamp %in% unlist(Map(
    `:`,
    Events$Event.start,
    Events$Event.end
  ))) %>%
  filter(InRange == "TRUE")

【问题讨论】:

  • A similar question 处理加入日期范围,但他们的示例在数据框之间有一个公共列。我无法评论他们的问题,因为我的代表太低了。
  • 这会产生你想要的结果吗? unlist(lapply(Probes.subset$Timestamp, function(x) which(x &gt;= Events$Event.start &amp; x &lt;= Events$Event.end)))。您可以将其分配给Probes.subset中的列
  • @Gopala - 我尝试运行它但得到以下错误:Error in $(*tmp*, "Event", value = c(1L, 1L, 1L, 1L, : replacement has 43 rows, data has 54
  • 是的 - 对不起。代替unlist,使用as.integer。它将正确填充缺失值。 as.integer(lapply(Probes.subset$Timestamp, function(x) which(x &gt;= Events$Event.start &amp; x &lt;= Events$Event.end, arr.ind = TRUE))).

标签: r dplyr


【解决方案1】:

在 SQL 中,您可以在加入时使用 as 为您的不同数据集指定别名。这允许您从每个数据集中选择特定列。采用该答案的代码,您可以这样做:

library(sqldf)
res <- sqldf("SELECT l.*, r.`Event.name`
       FROM Probes as l
       LEFT JOIN Events as r
       ON  l.Timestamp BETWEEN r.`Event.start` AND r.`Event.end`")

head(res)
#            Timestamp Value Event.name
#1 2016-06-01 01:00:00 60.73         NA
#2 2016-06-01 01:10:00 14.01         NA
#3 2016-06-01 01:20:00 17.14          1
#4 2016-06-01 01:30:00 43.64          1
#5 2016-06-01 01:40:00 27.05          1
#6 2016-06-01 01:50:00 57.10          1

请注意 - 我会小心您的数据设置,因为在 Events 的第 5 行中,您的开始时间 > 结束时间。


另外一个快速的data.table 解决方案是使用foverlaps

library(data.table)
setDT(Probes)[,Time2 := Timestamp] #Clean data
setDT(Events)[, `:=`(start = min(Event.start, Event.end), end = max(Event.start, Event.end)), by = (seq_len(nrow(Events)))]

setkey(setDT(Events), start, end)
res2 <- foverlaps(setDT(Probes), Events, by.x = c("Timestamp", "Time2"), nomatch = NA)[, c("Time2", "Event.start", "Event.end", "start","end") := NULL]

【讨论】:

  • 啊,我发帖后才找到的。现在就试试吧!
  • 效果很好!非常感谢您的帮助,这已经有一段时间了。我现在要开始在 R 中使用 SQL 了……还是个新手! +1
  • 没问题!我发现 SQL 非常适合这些类型的连接。此外,如果您担心我编辑的速度以包含快速data.table 方法。虽然语法不是超级友好
  • 我正在尝试对您建议的两种方法进行速度测试,但 data.table 方法一直说 unepeced ']' 我似乎无法修复该死的东西!您的第一个解决方案超级快,尽管它正在处理超过 180,000 行!
  • 是的,为了便于阅读,我编辑了最后一部分
猜你喜欢
  • 1970-01-01
  • 2018-12-19
  • 2022-09-26
  • 1970-01-01
  • 1970-01-01
  • 2017-08-17
  • 1970-01-01
  • 2021-07-09
相关资源
最近更新 更多