减少r中嵌套for循环的时间

时间:2016-10-26 15:54:47

标签: r for-loop

我试图从大约178,000行的数据集中提取一些信息。我有一个包含大约9个变量的数据框,但是这个部分只使用其中的3个。这些数据的一小部分可能如下所示:

date <- as.Date(c("2016-09-17", "2016-09-14", "2016-09-17", "2016-09-13","2016-09-17"))
idnum <- c("1", "2", "1", "1", "1")
hour <- round(as.numeric(c("15.75", "16.34", "16.12", "15.53", "17.10")), digits = 2)

all <- data.frame(date, idnum, hour)

给予:

   date      idnum     hour
2016-09-17     1      15.75
2016-09-14     2      16.34
2016-09-17     1      16.12
2016-09-13     1      15.53
2016-09-17     1      17.10

我的目标是确定每个日期每个ID在一小时内的使用次数(我称之为变量关闭)。最后,我的数据应如下所示:

   date      idnum     hour    close
2016-09-17     1      15.75      1
2016-09-14     2      16.34      0
2016-09-17     1      16.12      2
2016-09-13     1      15.53      0
2016-09-17     1      17.10      1

我已经获得以下代码来处理这个小数据集

all$close <- 0
m <- 1

for (i in m:nrow(all)) {
    for (j in 1:nrow(all)) {
        if(i != j & all$date[i] == all$date[j] & all$idnum[i] == idnum[j] 
          & abs(all$hour[i] - all$hour[j]) <= 1) {
           all$close[i] <- all$close[i] + 1                              
        } else {
          all$close[i] <- all$close[i]
        }
    }
    m = m + 1
}

但是,只要将其扩展为更多行,运行时间就会很长。在r中有更有效的方法吗?

1 个答案:

答案 0 :(得分:0)

对于已排序的向量xfindInterval(x+1, x) - findInterval(x-1, x)给出了每个观察(x[i]-1, x[i]+1)在指定时间间隔x[i]内的观察数量。

library(dplyr)     
all %>% 
  group_by(idnum, date) %>%
  arrange(hour) %>% 
  mutate(close1 = findInterval(hour+1, hour) - findInterval(hour-1, hour) - 1)

# Source: local data frame [5 x 4]
# Groups: idnum, date [3]

#        date  idnum  hour close
#       <date> <fctr> <dbl> <dbl>
# 1 2016-09-17      1 15.75     1
# 2 2016-09-14      2 16.34     0
# 3 2016-09-17      1 16.12     2
# 4 2016-09-13      1 15.53     0
# 5 2016-09-17      1 17.10     1

为了比较,

set.seed(1234)
date <- as.Date("2016-1-1") + sample(1:1000, 10000, TRUE)
idnum <- sample(1:100, 1e4, TRUE)
hour <- sample(0:239, 10000, TRUE)/10
all <- data.frame(date, idnum, hour)

system.time(
all <- all %>% 
  group_by(idnum, date) %>%
  arrange(hour) %>% 
  mutate(close1 = findInterval(hour+1, hour) - findInterval(hour-1, hour) - 1)
)
#   user  system elapsed 
#   0.25    0.00    0.27