在一个数据集中,我有大约3000000行(DF1),而在另一个数据集中,我有大约22行(DF2)。下面给出了我拥有的两个数据帧的示例。
DF1
DateTime REG
2018-07-01 12:00:00 NHDG
2018-07-12 11:55:23 NSKR
DF2
StartDateTime EndDateTime Direction
2018-07-01 07:55:11 2018-07-01 12:01:56 W
2018-07-12 11:00:23 2018-07-12 11:45:00 E当DateTime在StartDateTime和EndDateTime之间时,我想标记DF1中的任何内容。因此,输出如下所示:
DF1
DateTime REG Flag
2018-07-01 12:00:00 NHDG 1
2018-07-12 11:55:23 NSKR 0我目前使用的代码是:
#Flag if in delay or not
DF1$Flag<-0
for (i in 1:nrow(DF1)){
for (j in 1:nrow(DF2)){
if ((DF1$DateTime[i] >= DF2$StartDateTime[j]) & (DF1$DateTime <= DF2$EndDateTime[j])){
DF1$Flag[i]<-1
} else {
DF1$Flag[i]<-DF1$Flag
}
}
}如果可能的话,我非常高兴这段代码能被从for循环中去掉。
发布于 2019-02-12 18:40:31
如果我理解正确的话,如果DateTime位于DF2的任何间隔之间,那么DF1中的FLAG值应该设置为1,对吧?然后,下面的基本代码就可以完成这项工作:
DF1$Flag = sapply(DF1$DateTime,
function(x) as.integer(sum(x >= DF2$StartDateTime &
x <= DF2$EndDateTime) > 0))
# DateTime REG Flag
# 1 2018-07-01 12:00:00 NHDG 1
# 2 2018-07-12 11:55:23 NSKR 0这个想法是为了对比较进行矢量化:对于DF1中的每个DateTime (通过sapply进行“循环”),将值与DF2中的所有间隔(Start-和EndDateTime )进行比较,并对结果进行sum:如果sum大于0,则在DF2中至少有一行,其中来自DF1的DateTime位于其Start-和EndDateTime之间。然后,as.integer将sum(...) > 0的布尔输出转换为1或0。
而且,如果您想要更快的解决方案,可以使用dplyr
df1 = full_join(mutate(DF1, foo=1), mutate(DF2, foo=1), by='foo') %>%
mutate(Flag = as.integer(DateTime >= StartDateTime & DateTime <= EndDateTime)) %>%
group_by(DateTime) %>% slice(which.max(Flag)) %>%
select(DateTime, REG, Flag)否则:在DF2 (j循环)的行上的第二次循环似乎有问题:对于DF1的每一行,您将日期与连续的DF2所有行的开始和结束日期进行比较,基本上每次都覆盖结果标志值,并且只保留结果以便与DF2的最后一行进行比较...?换句话说,DF1$Flag[i] <- ...中的i不会在j循环中移动(每次都会被覆盖)。
因此,如果您只想比较DF2的最小和最大日期范围,您可以简单地执行以下操作:
DF1$Flag = as.integer((DF1$DateTime >= min(DF2$StartDateTime)) & (DF1$DateTime <= max(DF2$EndDateTime)))发布于 2019-02-12 18:52:18
那这个呢?
library(data.table)
DF1$flag <- as.numeric(sapply(seq(nrow(DF1)), function(x)
DF1[x, "DateTime"] %between% c(min(DF2[x, "StartDateTime"]), max(DF2[x, "EndDateTime"]))))
# DateTime REG flag
# 1 2018-07-01 12:00:00 NHDG 1
# 2 2018-07-12 11:55:23 NSKR 0Data
> dput(DF1)
structure(list(DateTime = structure(1:2, .Label = c("2018-07-01 12:00:00",
"2018-07-12 11:55:23"), class = "factor"), REG = structure(1:2, .Label = c("NHDG",
"NSKR"), class = "factor")), class = "data.frame", row.names = c(NA,
-2L))
> dput(DF2)
structure(list(StartDateTime = structure(1:2, .Label = c("2018-07-01 07:55:11",
"2018-07-12 11:00:23"), class = "factor"), EndDateTime = structure(1:2, .Label = c("2018-07-01 12:01:56",
"2018-07-12 11:45:00"), class = "factor"), Direction = structure(2:1, .Label = c("E",
"W"), class = "factor")), class = "data.frame", row.names = c(NA,
-2L))
DF1$DateTime <- as.POSIXct(DF1$DateTime)
DF2$StartDateTime <- as.POSIXct(DF2$StartDateTime)
DF2$EndDateTime <- as.POSIXct(DF2$EndDateTime)发布于 2019-02-12 19:00:04
也可以使用foverlaps
library(data.table)
setDT(DF1)[, DateTime := as.POSIXct(DateTime)][, EndDateTime := DateTime]
setDT(DF2)[, `:=` (StartDateTime = as.POSIXct(StartDateTime),
EndDateTime = as.POSIXct (EndDateTime))]
setkey(DF1, DateTime, EndDateTime)
setkey(DF2, StartDateTime, EndDateTime)
DF1[, Flag := foverlaps(DF1, DF2, type = "within", which = TRUE, mult = "first")][
is.na(Flag), Flag := 0][, EndDateTime := NULL]这将检查DF1中的每个日期是否位于DF2中的任何时间间隔内。
它也会很快,至少根据我的测试是这样。使用sapply进行基准测试
Unit: milliseconds
expr min lq mean median uq max neval
DT 4.752853 5.247319 18.38787 5.42855 6.950966 311.1944 25
sapply 9413.337014 10598.926908 11206.14866 10892.91751 11746.901293 13568.7995 25这是在DF1和DF2中分别包含10000行和12行的数据集上。
我只在300 000 / 22行上运行了一次,得到的结果如下:
Unit: seconds
expr min lq mean median uq max neval
DT 11.60865 11.60865 11.60865 11.60865 11.60865 11.60865 1
sapply 674.05823 674.05823 674.05823 674.05823 674.05823 674.05823 1https://stackoverflow.com/questions/54647852
复制相似问题