【问题标题】:How to aggregate data from 5 minutes to 30 minutes while keeping date intervals and other values如何在保持日期间隔和其他值的同时聚合 5 分钟到 30 分钟的数据
【发布时间】:2013-12-09 20:20:47
【问题描述】:

我有以下数据:

value <- c(1.869, 1.855, 1.855, 1.855, 1.855, 1.855, 1.855, 1.848, 1.848, 1.848, 1.848, 1.848, 1.848, 1.849)
date <- c("2013-08-28 08:00:00 UTC", "2013-08-28 08:05:00 UTC", "2013-08-28 08:10:00 UTC", "2013-08-28 08:15:00 UTC", "2013-08-28 08:20:00 UTC", "2013-08-28 08:25:00 UTC", "2013-08-28 08:30:00 UTC", "2013-08-28 08:35:00 UTC", "2013-08-28 08:40:00 UTC", "2013-08-28 08:45:00 UTC", "2013-08-28 08:50:00 UTC", "2013-08-28 08:55:00 UTC", "2013-08-28 09:00:00 UTC", "2013-08-28 09:05:00 UTC")
indicator <- c(1,0,0,1,0,0,0,0,0,0,0,0,0,1)

data <- data.frame(date=date,value=value, indicator=indicator)

我想做两件事。首先,我希望将其聚合/求和到 30 分钟的水平,但以 :00 和 :30 结尾。例如,此数据中的第一个值不会包含在计算中,但 8:05 到 8:30 会聚合到 8:30、8:35 到 9:00 到 9:00,等等。我还想汇总指标值。所以,如果有一个 1,我希望有一个 1(我猜 sum 也可以,因为它不是零)。

我已尝试使用 zoo 包中的 rollapply(有效,但我必须手动确保数据从 8:05 开始),但我想保留日期并汇总指标:

aggdata <- rollapply(data=data$value,width=6,FUN=sum,by=6)

不包含完整 30 分钟间隔的数据对我来说毫无用处,因此我宁愿不包含该数据。我想要的输出是:

date                       value  indicator
"2013-08-28 08:00:00 UTC"  1.869  1
"2013-08-28 08:30:00 UTC"  11.13  1
"2013-08-28 09:00:00 UTC"  11.088 0 
"2013-08-28 09:05:00 UTC"  1.849  1

或者更好:

date                       value  indicator
"2013-08-28 08:00:00 UTC"  NA     NA
"2013-08-28 08:30:00 UTC"  11.13  1
"2013-08-28 09:00:00 UTC"  11.088 0 
"2013-08-28 09:05:00 UTC"  NA     NA

甚至更好:

date                       value  indicator
"2013-08-28 08:30:00 UTC"  11.13  1
"2013-08-28 09:00:00 UTC"  11.088 0 

【问题讨论】:

    标签: r aggregate zoo


    【解决方案1】:

    这似乎也是正确的:

    data$date <- as.POSIXct(as.character(data$date))
    
    interval <- seq(min(data$date), max(data$date), "30 mins")
    
    intervals <- c(data$date[1], interval + 5*60)
    
    res <- na.omit(aggregate(list(value = data$value, indicator = data$indicator), 
                                    list(date = findInterval(data$date, intervals)), 
                                          function(x) if(length(x) == 6) sum(x) else NA))
    
    res$date <- interval[res$date]
    
    res
    #                 date  value indicator
    #2 2013-08-28 08:30:00 11.130         1
    #3 2013-08-28 09:00:00 11.088         0
    

    【讨论】:

      【解决方案2】:

      这应该做的工作

      ## convert from string to date (POSIX)
      dt <- strptime(data$date,format="%Y-%m-%d %H:%M:%S")
      ## create bins to collect the right periods
      ##  1) subtract the modulo to 30min (-> 30 min bins)
      ##  2) add 30 if this modulo is not 0 (-> they and at :00 or :30)
      bins <- strftime(as.POSIXct(dt+60*(-(dt$min %% 30)
                                         + ifelse(dt$min %% 30,30,0)),
                                  origin="1970-01-01"),'%Y-%m-%d %H:%M')
      ## use this bins
      data.frame(value=tapply(data$value,bins,sum),
                 indicator=tapply(data$indicator,bins,
                   function(x) ifelse(sum(x),1,0)))
      

      【讨论】:

        【解决方案3】:
        > z <- read.zoo(data, FUN = identity)
        > zr <- rollapplyr(z[-1, ], 6, sum, by = 6)
        > zr
                                 value indicator
        2013-08-28 08:30:00 UTC 11.130         1
        2013-08-28 09:00:00 UTC 11.088         0
        

        尽管将其留在动物园中以将其转换回数据框可能会更好:fortify.zoo

        library(ggplot2)
        fortify(zr)
        

        【讨论】:

        • 我喜欢这个答案,除了z[-1, ] 部分——也就是说,您需要检查数据,然后明确排除代码中的第一行。
        【解决方案4】:

        要聚合 8:05 到 8:30 并将其报告为 8:30(即,在聚合间隔结束时报告时间),并忽略任何不包含 6 个观测值的 30 分钟间隔,请使用以下:

        data$date <- as.POSIXct(data$date)
        data$date.30min <- as.POSIXct(ceiling(as.numeric(data$date) / (30 * 60)) *
          (30 * 60), origin='1970-01-01')
        sumif6 <- function(x) {
          if(length(x) == 6) sum(x) else NA
        }
        res30 <- na.omit(aggregate(cbind(value, indicator) ~ date.30min, data, sumif6))
        res30
        #           date.30min  value indicator
        #2 2013-08-28 08:30:00 11.130         1
        #3 2013-08-28 09:00:00 11.088         0
        

        如果您需要聚合 8:00 到 8:25 并将其报告为 8:00(即在聚合间隔开始时报告时间),只需使用 floor() 而不是上限:

        data$date.30min <- as.POSIXct(floor(as.numeric(data$date) / (30 * 60)) *
          (30 * 60), origin='1970-01-01')
        

        如果您需要聚合 15 分钟而不是 30 分钟,只需将 30s 替换为 15s,并创建一个新的 sumif3 函数:

        data$date.15min <- as.POSIXct(floor(as.numeric(data$date) / (15 * 60)) *
          (15 * 60), origin='1970-01-01')
        sumif3 <- function(x) {
          if(length(x) == 3) sum(x) else NA
        }
        res15 <- na.omit(aggregate(cbind(value, indicator) ~ date.15min, data, sumif3))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-08-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-30
          • 1970-01-01
          • 2021-12-12
          • 2019-09-28
          相关资源
          最近更新 更多