提高R中的效率循环以进行日期比较和数据集创建

时间:2017-07-18 13:33:08

标签: r loops date for-loop

我有一个名为DateTime的数据集,其中包含一个ID为ID的列,一个包含其访问开始日期的列以及一个包含其访问结束日期的列。我想创建一个包含两列的数据集,其中第一列给出一天的日期和小时,第二列给出存在的ID。因此,如果在特定日期的某个小时出现两个ID,则会创建两行。 为此,我创建了数据框Presence以将这些存储到列,并使日期列具有正确的格式。我还有一个向量日期,其中包含第一个开始日期和最后结束日期之间的所有可能日期和小时。

我创建了第一个for循环来检查每秒ID for循环以检查每个日期,如果日期之间有重叠,则数据存储在Presence中。但是,我必须让这个包含6万个ID和11000个可能日期的数据集。现在已经运行了4个多小时。这并不让我感到惊讶,但必须有更快的方法来实现这一点。

Presence=data.frame(matrix(vector(), 5000000, 2), stringsAsFactors = FALSE)
Presence<- data.frame(Date= Presence[,1], ID= Presence[,2])
Presence$Date<-as.POSIXct(strptime(Presence$Date, format="%Y-%m-%d %H:%M:%S"), tz = "Europe/Brussels")

k=1

for (i in 1:length(DateTime$ID)){
for (j in 1:length(Dates)){
   if ((DateTime$START_DATE[i]<Dates[j]) & (DateTime$END_DATE[i]>Dates[j]) ){
  Presence$Date[k]<-as.POSIXct(strptime(Dates[j], "%Y-%m-%d %H:%M:%S"), tz = "Europe/Brussels")
  Presence$ID[k]<-DateTime$ID[i]
  k=k+1}

}
}

有人可以帮我吗?我不是R专家,所以我可能会不必要地解决这个问题。谢谢!

2 个答案:

答案 0 :(得分:1)

您可以使用包melt中的reshape2

首先我们构建数据

set.seed(1)
DateTime = data.frame(id = 1:10,START_DATE = Sys.Date()+ (1:10),END_DATE = Sys.Date()+ (1:10) + sample(0:10,10))

# > DateTime
#    id START_DATE   END_DATE
# 1   1 2017-07-19 2017-07-21
# 2   2 2017-07-20 2017-07-23
# 3   3 2017-07-21 2017-07-26
# 4   4 2017-07-22 2017-07-29
# 5   5 2017-07-23 2017-07-24
# 6   6 2017-07-24 2017-08-01
# 7   7 2017-07-25 2017-07-29
# 8   8 2017-07-26 2017-08-05
# 9   9 2017-07-27 2017-08-02
# 10 10 2017-07-28 2017-07-28

请注意,最后一行的开始和结束日期相同

然后我们使用包melt

中的reshape2
library(reshape2)
library(dplyr)
DateTime %>% melt(id.vars="id") %>% select(-variable) %>% unique
# id      value
# 1   1 2017-07-19
# 2   2 2017-07-20
# 3   3 2017-07-21
# 4   4 2017-07-22
# 5   5 2017-07-23
# 6   6 2017-07-24
# 7   7 2017-07-25
# 8   8 2017-07-26
# 9   9 2017-07-27
# 10 10 2017-07-28
# 11  1 2017-07-21
# 12  2 2017-07-23
# 13  3 2017-07-26
# 14  4 2017-07-29
# 15  5 2017-07-24
# 16  6 2017-08-01
# 17  7 2017-07-29
# 18  8 2017-08-05
# 19  9 2017-08-02

id = 10只有一行,其他人只有

你也可以使用基函数reshape

unique(reshape(DateTime,varying = c("START_DATE","END_DATE"),direction="long",v.names = "date")[,c("id","date")])

答案 1 :(得分:0)

您尝试执行的操作称为重叠连接,data.table::foverlaps函数是R中的一个有效实现。以下应该产生您想要的内容:

library(data.table)
UniqueDates <-  unique(c(DateTime$START_DATE, DateTime$END_DATE))
Dates <- Dates[order(Dates)]
Dates <- data.frame(Date = UniqueDates, Date1 = UniqueDates, Date2 = UniqueDates)
Dates <- setDT(Dates, key = c("Date", "Dates1", "Dates2"))
DateTime <- setDT(DateTime, key=c("id", "START_DATE", "END_DATE"))
Presence <- foverlaps(Dates, DateTime, type = "within", mult = "all", nomatch = 0)
setDF(Presence)
Presence <- Presence[, c("Date", "id")]

您可能需要修改输入日期向量以满足您的需求。除非您的可用内存允许,否则您可能必须在输入data.frame的子集上使用上述内容,然后将结果合并。