【问题标题】:Subset sequential times (chron) and aggregate them子集顺序时间(chron)并聚合它们
【发布时间】:2013-07-30 20:58:21
【问题描述】:

我有大量的电压读数数据集。我希望确定电压高于阈值的不同时间段的频率。因此,对于电压子集(> = 2V),我希望计算连续周期的长度,其中电压基于 1 秒的采样间隔。请参阅下面的示例数据:

library(chron)
volts=c(2,3,4,5,6,2,2,3,4,5,5,5)
t=chron(times=c("23:03:20", "23:03:21", "23:03:22", "23:03:23","23:03:24","23:03:25","04:01:50","04:01:51","04:01:52","04:01:53","04:01:54","04:01:55"))
data=data.frame(volts,"time"=t)

这个例子有两个感兴趣的系列,一个从 23:03:20 到 23:03:25,一个从 04:01:50 到 04:01:55。

我希望计算这些周期的持续时间和大量数据的平均电压,条件是周期之间有 30 秒的间隔,以便将它们视为离散的。我怀疑我的答案可能取决于动物园,我欢迎提出建议。

【问题讨论】:

  • +1 用于明确说明的问题。如果你也告诉我们你尝试了什么,那就太好了......
  • 会有多个跨日过渡吗? 23:59:5900:00:02 之间的差异应该计算为 3 秒,还是(24 小时 - 3 秒)?

标签: r


【解决方案1】:

在输出中使用与@BenBolker 相同的名称:

library(data.table)
dt = data.table(data)

dt[, time := as.ITime(time)] # easier to deal with

dt[, list(meanvolts = mean(volts), duration = time[.N] - time[1], n = .N),
     by = list(period = 1 + c(0, cumsum(abs(diff(time)) >= 30)))]
#   period meanvolts duration n
#1:      1  3.666667 00:00:05 6
#2:      2  4.000000 00:00:05 6

【讨论】:

  • 我没有仔细考虑过,但你确定abs(diff(time))>=30 在日期范围内正常工作,例如在23:59:5900:00:02 之间? (它适用于指定的输入,它在日边界上有更大的差距......)
  • @BenBolker endpoints 创建索引比cumsum 快,但data.table 在其余进程(循环和绑定)中是无与伦比的
  • @BenBolker 好点。在使用endpoints 之前,我的解决方案将因其他原因而无法工作。由于我将2013-07-30 添加到time 以将其转换为POSIXct。我会得到2013-07-30 00:00:02 而不是预期的2013-07-31 00:00:02
  • @BenBolker 取决于“正确”的定义,因为没有指定日期,所以不清楚这是 3 秒还是 ~24 小时的差异——这将假设这是 ~24 小时的差异
  • 也许 OP 可以澄清一下。我认为这些应该是连续几天。
【解决方案2】:

zoo 可能有更有效的解决方案,但是怎么样:

样本数据(为方便起见重复)

library(chron)
dat <- data.frame(volts=c(2,3,4,5,6,2,2,3,4,5,5,5),
  time=chron(times=c("23:03:20", "23:03:21", "23:03:22", 
             "23:03:23","23:03:24","23:03:25",
              "04:01:50","04:01:51","04:01:52","04:01:53",
              "04:01:54","04:01:55")))

分析:

daysecs <- 3600*24
dd <- c(unclass(diff(dat$time))*daysecs)   ## difference in seconds
## classify jumps to new periods, including day boundaries 
## (I haven't tested this carefully!)
new_per <- !((dd>0 & dd<30) | (dd<0 & dd<(-daysecs+30))) 
dat$period <- 1+c(0,cumsum(new_per)) ## a fairly standard trick
library(plyr)
ddply(dat,.(period),summarise,
      meanvolts=mean(volts),
      duration=tail(time,1)-time[1],
      n=length(volts))

结果:

##   period meanvolts duration n
## 1      1  3.666667 00:00:05 6
## 2      2  4.000000 00:00:05 6

plyr 特别不是超快,但我会在您的数据上尝试一下,看看它是否可以接受,然后再返回并让我们了解它必须有多快(编辑您的问题(“我有 600 万个电压测量值......”)或发布一个链接到这个的新问题)

【讨论】:

    【解决方案3】:

    这里有一个解决方案xts 包。一般我们使用period.apply函数来处理这样的时序过程。这里实际上,我只使用endpoints 创建拆分器索引(每 30 秒),然后使用经典的 sapply 循环。

    library(xts)
    ## creating the `xts` objects.
    x.z <- xts(data$volts,
               as.POSIXct(strptime(data$time,format='%H:%M:%S')))
    
    INDEX <- endpoints(x.z,'secs',30)
    xx <- sapply(1:(length(INDEX) - 1), function(y) {
      x <- x.z[(INDEX[y] + 1):INDEX[y + 1]]
      data.frame(period=y,
                 duration=diff(range(index(x))),
                 mm = mean(x),
                 len = length(x))
    })
    
    
    t(xx)
         period duration mm       len
    [1,] 1      5        4        6  
    [2,] 2      5        3.666667 6  
    

    编辑endpoints如何处理时间索引超过天边界的特殊情况?

    创建示例:

    ## creating xts object index
    ii <- as.POSIXct(strptime(data$time,format='%H:%M:%S'))
    ## here I add  day to simulate day boundary
    ii[6]  <- as.POSIXct(ii[6] + as.difftime(1,units='days'))
    

    现在我的时间系列看起来像:

        x.z
                        [,1]
    2013-07-31 04:01:50    2
    2013-07-31 04:01:51    3
    2013-07-31 04:01:52    4
    2013-07-31 04:01:53    5
    2013-07-31 04:01:54    5
    2013-07-31 04:01:55    5
    2013-07-31 23:59:55    2
    2013-07-31 23:59:56    3
    2013-07-31 23:59:57    4
    2013-07-31 23:59:58    5
    2013-07-31 23:59:59    6
    2013-08-01 00:00:02    2   ## day boundaries here
    

    应用相同的代码(解决方案的开头),我们得到 3 个句点,而不是预期的 2 个

     t(xx)
         period duration mm len
    [1,] 1      5        4  6  
    [2,] 2      4        4  5  
    [3,] 3      0        2  1    ## 2013-08-01 00:00:02    2 
    

    【讨论】:

      猜你喜欢
      • 2021-10-26
      • 2018-04-26
      • 2015-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-04
      • 2019-04-16
      • 1970-01-01
      相关资源
      最近更新 更多