首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >加速double for循环

加速double for循环
EN

Stack Overflow用户
提问于 2019-02-12 18:24:01
回答 4查看 66关注 0票数 0

在一个数据集中,我有大约3000000行(DF1),而在另一个数据集中,我有大约22行(DF2)。下面给出了我拥有的两个数据帧的示例。

代码语言:javascript
复制
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中的任何内容。因此,输出如下所示:

代码语言:javascript
复制
DF1  
DateTime                 REG      Flag
2018-07-01 12:00:00      NHDG      1
2018-07-12 11:55:23      NSKR      0

我目前使用的代码是:

代码语言:javascript
复制
#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循环中去掉。

EN

回答 4

Stack Overflow用户

发布于 2019-02-12 18:40:31

如果我理解正确的话,如果DateTime位于DF2的任何间隔之间,那么DF1中的FLAG值应该设置为1,对吧?然后,下面的基本代码就可以完成这项工作:

代码语言:javascript
复制
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.integersum(...) > 0的布尔输出转换为10

而且,如果您想要更快的解决方案,可以使用dplyr

代码语言:javascript
复制
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的最小和最大日期范围,您可以简单地执行以下操作:

代码语言:javascript
复制
DF1$Flag = as.integer((DF1$DateTime >= min(DF2$StartDateTime)) & (DF1$DateTime <= max(DF2$EndDateTime)))
票数 2
EN

Stack Overflow用户

发布于 2019-02-12 18:52:18

那这个呢?

代码语言:javascript
复制
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    0

Data

代码语言:javascript
复制
> 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)
票数 0
EN

Stack Overflow用户

发布于 2019-02-12 19:00:04

也可以使用foverlaps

代码语言:javascript
复制
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进行基准测试

代码语言:javascript
复制
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

这是在DF1DF2中分别包含10000行和12行的数据集上。

我只在300 000 / 22行上运行了一次,得到的结果如下:

代码语言:javascript
复制
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     1
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54647852

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档