【问题标题】:Check if Posixct time is within interval检查 Posixct 时间是否在间隔内
【发布时间】:2016-06-17 21:20:47
【问题描述】:

问题: 我有两个要合并的数据帧,具体取决于一个数据帧的日期/时间是否在另一个数据帧的间隔内。

流量:日期和时间(Posixct)、频率

mydata:区间、频率总和

我现在想计算来自流量的 Posixct 时间是否在 mydata 的区间内,如果为真,我想计算 mydata 中“频率总和”列中的频率。

我遇到的两个问题: 1.交通数据框的行数明显多于mydata。我不知道如何告诉 R 循环遍历流量中的每个观察结果以检查 mydata 中的一行。

  1. 在 mydata 的频率区间中可以有多个观测拟合。我希望 R 将不同交通观察的所有频率相加以获得频率的总分。间隔也是重叠的。

这是数据:

DateTime <- c("2014-11-01 04:00:00", "2014-11-01 04:03:00",  "2014-11-01 04:06:00", "2014-11-01 04:08:00", "2014-11-01 04:10:00", "2014-11-01 04:12:00", "2015-08-01 04:13:00", "2015-08-01 04:45:00", "2015-08-01 14:15:00", "2015-08-01 14:13:00")
DateTime <- as.POSIXct(DateTime)
Frequency <- c(1,2,3,5,12,1,2,2,1,1)                 
traffic <- data.frame(DateTime, Frequency)

library(lubridate)
DateTime1 <- c("2014-11-01 04:00:00", "2015-08-01 04:03:00",  "2015-08-01 14:00:00")
DateTime2 <- c("2014-11-01 04:15:00", "2015-08-01 04:13:00",  "2015-08-01 14:15:00")
DateTime1 <- as.POSIXct(DateTime1)
DateTime2 <- as.POSIXct(DateTime2)
mydata <- data.frame(DateTime1, DateTime2)
mydata$Interval <- as.interval(DateTime1, DateTime2)
mydata$SumFrequency <- NA

预期的结果应该是这样的:

mydata$SumFrequency <- c(24, 2, 2)
head(mydata)

我尝试了 lubridate 包中的 int_overlaps。 非常感谢任何有关如何解决此问题的提示!

【问题讨论】:

    标签: r count intervals lubridate


    【解决方案1】:

    data.table 包中foverlaps 的简短解决方案:

    mydata <- data.table(DateTime1, DateTime2, key = c("DateTime1", "DateTime2"))
    traffic <- data.table(start = DateTime, end = DateTime, Frequency, key = c("start","end"))
    
    foverlaps(traffic, mydata, type="within", nomatch=0L)[, .(sumFreq = sum(Frequency)), 
                                                          by = .(DateTime1, DateTime2)]
    

    给出:

                 DateTime1           DateTime2 sumFreq
    1: 2014-11-01 04:00:00 2014-11-01 04:15:00      24
    2: 2015-08-01 04:03:00 2015-08-01 04:13:00       2
    3: 2015-08-01 14:00:00 2015-08-01 14:15:00       2
    

    【讨论】:

      【解决方案2】:

      使用data.table 方法和between 按时过滤流量数据集:

      setDT(traffic)
      setDT(mydata)
      
      mydata[,SumFrequency := as.numeric(SumFrequency)] # coerce logical to numeric for next step.
      mydata[,SumFrequency := sum( traffic[ DateTime %between% c(DateTime1, DateTime2), Frequency] ), by=1:nrow(mydata)] 
      

      给:

                   DateTime1           DateTime2                                           Interval SumFrequency
      1: 2014-11-01 04:00:00 2014-11-01 04:15:00   2014-11-01 04:00:00 CET--2014-11-01 04:15:00 CET           24
      2: 2015-08-01 04:03:00 2015-08-01 04:13:00 2015-08-01 04:03:00 CEST--2015-08-01 04:13:00 CEST            2
      3: 2015-08-01 14:00:00 2015-08-01 14:15:00 2015-08-01 14:00:00 CEST--2015-08-01 14:15:00 CEST            2
      

      如果mydata中有很多行,最好创建一个索引列并在by子句中使用:

      mydata[, idx := .I]
      mydata[, SumFrequency := sum( traffic[DateTime %between% c(DateTime1, DateTime2),Frequency] ),by=idx]
      

      这给出了:

                   DateTime1           DateTime2                                           Interval SumFrequency idx
      1: 2014-11-01 04:00:00 2014-11-01 04:15:00   2014-11-01 04:00:00 CET--2014-11-01 04:15:00 CET           24   1
      2: 2015-08-01 04:03:00 2015-08-01 04:13:00 2015-08-01 04:03:00 CEST--2015-08-01 04:13:00 CEST            2   2
      3: 2015-08-01 14:00:00 2015-08-01 14:15:00 2015-08-01 14:00:00 CEST--2015-08-01 14:15:00 CEST            2   3
      

      【讨论】:

        【解决方案3】:

        我看到了两种解决方案:

        使用data.frameplyr

        您可以使用 lubridate 中的 %within% 函数和 for 循环或使用 plyr 循环函数(如 dlply)来完成此操作

        DateTime <- c("2014-11-01 04:00:00", "2014-11-01 04:03:00",  "2014-11-01 04:06:00", "2014-11-01 04:08:00", "2014-11-01 04:10:00", "2014-11-01 04:12:00", "2015-08-01 04:13:00", "2015-08-01 04:45:00", "2015-08-01 14:15:00", "2015-08-01 14:13:00")
        DateTime <- as.POSIXct(DateTime)
        Frequency <- c(1,2,3,5,12,1,2,2,1,1)                 
        traffic <- data.frame(DateTime, Frequency)
        
        library(lubridate)
        DateTime1 <- c("2014-11-01 04:00:00", "2015-08-01 04:03:00",  "2015-08-01 14:00:00")
        DateTime2 <- c("2014-11-01 04:15:00", "2015-08-01 04:13:00",  "2015-08-01 14:15:00")
        DateTime1 <- as.POSIXct(DateTime1)
        DateTime2 <- as.POSIXct(DateTime2)
        mydata <- data.frame(DateTime1, DateTime2)
        mydata$Interval <- as.interval(DateTime1, DateTime2)
        
        library(plyr)
        # Create a group-by variable
        mydata$NumInt <- 1:nrow(mydata)
        mydata$SumFrequency <- dlply(mydata, .(NumInt),
                                     function(row){
                                       sum(
                                         traffic[traffic$DateTime %within% row$Interval, "Frequency"]
                                       )
                                     })
        
        mydata
        #>             DateTime1           DateTime2
        #> 1 2014-11-01 04:00:00 2014-11-01 04:15:00
        #> 2 2015-08-01 04:03:00 2015-08-01 04:13:00
        #> 3 2015-08-01 14:00:00 2015-08-01 14:15:00
        #>                                             Interval NumInt SumFrequency
        #> 1   2014-11-01 04:00:00 CET--2014-11-01 04:15:00 CET      1           24
        #> 2 2015-08-01 04:03:00 CEST--2015-08-01 04:13:00 CEST      2            2
        #> 3 2015-08-01 14:00:00 CEST--2015-08-01 14:15:00 CEST      3            2
        

        带有data.table 和函数foverlaps

        data.table 已经实现了一个用于重叠连接的功能,您可以通过一些小技巧在您的情况下使用它。
        这个函数是foverlaps(我在下面使用data.table 1.9.6
        (见How to perform join over date ranges using data.table?and this presentation

        请注意,您不需要使用lubridate 创建间隔

        DateTime <- c("2014-11-01 04:00:00", "2014-11-01 04:03:00",  "2014-11-01 04:06:00", "2014-11-01 04:08:00", "2014-11-01 04:10:00", "2014-11-01 04:12:00", "2015-08-01 04:13:00", "2015-08-01 04:45:00", "2015-08-01 14:15:00", "2015-08-01 14:13:00")
        DateTime <- as.POSIXct(DateTime)
        Frequency <- c(1,2,3,5,12,1,2,2,1,1)                 
        traffic <- data.table(DateTime, Frequency)
        
        library(lubridate)
        DateTime1 <- c("2014-11-01 04:00:00", "2015-08-01 04:03:00",  "2015-08-01 14:00:00")
        DateTime2 <- c("2014-11-01 04:15:00", "2015-08-01 04:13:00",  "2015-08-01 14:15:00")
        mydata <- data.table(DateTime1 = as.POSIXct(DateTime1), DateTime2 = as.POSIXct(DateTime2))
        
        # Use function `foverlaps`  for overlapping joins
        
        # Here's the trick : create a dummy variable to artificially have an interval
        traffic[, dummy:=DateTime]
        setkey(mydata, DateTime1, DateTime2)
        
        # do the join
        mydata2 <- foverlaps(traffic, mydata, by.x=c("DateTime", "dummy"), type ="within", nomatch=0L)[, dummy := NULL][]
        mydata2
        #>              DateTime1           DateTime2            DateTime Frequency
        #> 1: 2014-11-01 04:00:00 2014-11-01 04:15:00 2014-11-01 04:00:00         1
        #> 2: 2014-11-01 04:00:00 2014-11-01 04:15:00 2014-11-01 04:03:00         2
        #> 3: 2014-11-01 04:00:00 2014-11-01 04:15:00 2014-11-01 04:06:00         3
        #> 4: 2014-11-01 04:00:00 2014-11-01 04:15:00 2014-11-01 04:08:00         5
        #> 5: 2014-11-01 04:00:00 2014-11-01 04:15:00 2014-11-01 04:10:00        12
        #> 6: 2014-11-01 04:00:00 2014-11-01 04:15:00 2014-11-01 04:12:00         1
        #> 7: 2015-08-01 04:03:00 2015-08-01 04:13:00 2015-08-01 04:13:00         2
        #> 8: 2015-08-01 14:00:00 2015-08-01 14:15:00 2015-08-01 14:15:00         1
        #> 9: 2015-08-01 14:00:00 2015-08-01 14:15:00 2015-08-01 14:13:00         1
        
        # summarise with a sum by grouping by each line of mydata
        setkeyv(mydata2, key(mydata))
        mydata2[mydata, .(SumFrequency = sum(Frequency)), by = .EACHI]
        #>              DateTime1           DateTime2 SumFrequency
        #> 1: 2014-11-01 04:00:00 2014-11-01 04:15:00           24
        #> 2: 2015-08-01 04:03:00 2015-08-01 04:13:00            2
        #> 3: 2015-08-01 14:00:00 2015-08-01 14:15:00            2
        

        【讨论】:

        • 您的 foverlaps 解决方案相当冗长,请参阅我的回答,了解如何使其更短
        • 无需更新您的答案,这会使它们完全相同,这不是 imo 的目的
        【解决方案4】:

        就第 2 点而言,您可以使用聚合为例

        aggData <- aggregate(traffic$Frequency~format(traffic$DateTime, "%Y%m%d h:m"), data=traffic, sum)
        

        这会以分钟为单位汇总所有频率。

        对于第 1 点。合并不起作用吗?

        merge(x = myData, y = aggData, by = "DateTime", all.x = TRUE)  
        

        外合并解释here

        【讨论】:

        • 如果您在aggregate 中使用data 参数,则无需显式调用变量。
        • 不幸的是它不起作用。流量数据已经聚合到我需要的聚合点。一旦计算确定几个数据点在一个区间内,我想聚合不同行的频率。使用合并时,它会添加频率列,但仅返回 NA。
        【解决方案5】:

        使用for.loop,我们可以这样做:

        for(i in 1:nrow(mydata)) {
          mydata$SumFrequency[i] <- sum(traffic$Frequency[traffic$DateTime %within% mydata$Interval[i]])
        }
        
        > mydata
        #            DateTime1           DateTime2                                           Interval SumFrequency
        #1 2014-11-01 04:00:00 2014-11-01 04:15:00   2014-11-01 04:00:00 CET--2014-11-01 04:15:00 CET           24
        #2 2015-08-01 04:03:00 2015-08-01 04:13:00 2015-08-01 04:03:00 CEST--2015-08-01 04:13:00 CEST            2
        #3 2015-08-01 14:00:00 2015-08-01 14:15:00 2015-08-01 14:00:00 CEST--2015-08-01 14:15:00 CEST            2
        

        【讨论】:

          猜你喜欢
          • 2021-06-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多