按时间间隔对值进行求和的优雅方法(同时考虑缺失值)

时间:2018-04-12 23:24:06

标签: r

我想尝试这样的事情

df <- data.frame(times = c("0915", "0930", "0945", "1000", "1015", "1030", "1045", "1100", "1130", "1145", "1200"),
                 values = c(1,2,3,4,1,2,3,4,1,3,4))

> df
   times values
1   0915      1
2   0930      2
3   0945      3
4   1000      4
5   1015      1
6   1030      2
7   1045      3
8   1100      4
9   1130      1
10  1145      3
11  1200      4
12  1215      1
13  1245      3
14  1300      4
15  1330      2
16  1345      4

把它变成这样的东西

> df2
  times values
1   0930      3
2   1000      7
3   1030      3
4   1100      7
5   1130     NA
6   1200      7
7   1230     NA
8   1300      7
9   1330     NA
10  1400     NA

基本上,以15分钟的间隔测量值,并将它们转换为30分钟间隔内测量的值(求和就足够了)。

如果我能确定每半小时读一次我有两个15分钟的读数,我可以想出一个好的解决方案。我可以成对添加元素并获得我想要的东西。但我无法确定我的数据集。正如我的演示所示,可能会缺少多个连续值。

所以我认为有必要进行某种数字识别,例如认识到时间是在9:15到9:30之间,并将这两者相加。所以我有一个已经被称为hr2dec的函数,我创建它来将这些时间转换为十进制,所以它看起来像这样

> hr2dec(df$times)
 [1]  9.25  9.50  9.75 10.00 10.25 10.50 10.75 11.00 11.50 11.75 12.00

我提到这个,以防止用十进制而不是4位数时间来解决这个问题。

我也有24小时和多天的数据。因此,如果我有一个循环的解决方案,则需要在0015之后重置为2400,因为这些是每天的第一次和最后一次测量。包含日期的完整数据集可以像这样生成(包含时间的小数,就像我说的那样,对我来说也没问题):

set.seed(42)
full_df <- data.frame(date = rep(as.Date(c("2010-02-02", "2010-02-03")), each = 96),
                      dec_times = seq(0.25,24,0.25),
                      values = rnorm(96)
                      )

full_df <- full_df[-c(2,13,15,19,95,131,192),]

到目前为止,我能想出的最佳解决方案是成对比较循环。但即使这样也不完美。

有什么优雅的方式来做我想要的事情吗?即检查第一个和最后一个值(就日期和时间而言),并将每半个小时间隔相加?我对我的循环不满意......

  1. 检查第一个和最后一个日期时间值以计算半小时的范围
  2. 按顺序检查项目,一次配对以决定我是否有两个属于该半小时的值。
  3. 如果我这样做,请加上NA,如果我不这样做。

2 个答案:

答案 0 :(得分:1)

您应该查看tibbletime package - 具体来说,您需要查看在一段时间内折叠collapse_by()个对象的tbl_time

library(tibbletime)
library(dplyr)

# create a series of 7 days
# 2018-01-01 to 2018-01-07 by 15 minute intervals
df <- create_series('2018-01-01' ~ '2018-01-07', period = "15 minute")
df$values <- rnorm(nrow(df))
df
#> # A time tibble: 672 x 2
#> # Index: date
#>    date                 values
#>    <dttm>                <dbl>
#>  1 2018-01-01 00:00:00 -0.365 
#>  2 2018-01-01 00:15:00 -0.275 
#>  3 2018-01-01 00:30:00 -1.50  
#>  4 2018-01-01 00:45:00 -1.64  
#>  5 2018-01-01 01:00:00 -0.341 
#>  6 2018-01-01 01:15:00 -1.05  
#>  7 2018-01-01 01:30:00 -0.544 
#>  8 2018-01-01 01:45:00 -1.10  
#>  9 2018-01-01 02:00:00  0.0824
#> 10 2018-01-01 02:15:00  0.477 
#> # ... with 662 more rows

# Collapse into 30 minute intervals, group, and sum
df %>% 
  collapse_by("30 minute") %>%
  group_by(date) %>%
  summarise(sum_values = sum(values))
#> # A time tibble: 336 x 2
#> # Index: date
#>    date                sum_values
#>    <dttm>                   <dbl>
#>  1 2018-01-01 00:15:00     -0.640
#>  2 2018-01-01 00:45:00     -3.14 
#>  3 2018-01-01 01:15:00     -1.39 
#>  4 2018-01-01 01:45:00     -1.64 
#>  5 2018-01-01 02:15:00      0.559
#>  6 2018-01-01 02:45:00      0.581
#>  7 2018-01-01 03:15:00     -1.50 
#>  8 2018-01-01 03:45:00      1.36 
#>  9 2018-01-01 04:15:00      0.872
#> 10 2018-01-01 04:45:00     -0.835
#> # ... with 326 more rows

# Alternatively, you can use clean = TRUE
df %>% 
  collapse_by("30 minute", clean = TRUE) %>%
  group_by(date) %>%
  summarise(sum_values = sum(values))
#> # A time tibble: 336 x 2
#> # Index: date
#>    date                sum_values
#>    <dttm>                   <dbl>
#>  1 2018-01-01 00:30:00     -0.640
#>  2 2018-01-01 01:00:00     -3.14 
#>  3 2018-01-01 01:30:00     -1.39 
#>  4 2018-01-01 02:00:00     -1.64 
#>  5 2018-01-01 02:30:00      0.559
#>  6 2018-01-01 03:00:00      0.581
#>  7 2018-01-01 03:30:00     -1.50 
#>  8 2018-01-01 04:00:00      1.36 
#>  9 2018-01-01 04:30:00      0.872
#> 10 2018-01-01 05:00:00     -0.835
#> # ... with 326 more rows

如果你更喜欢视频(<20分钟),请查看David Vaughan的The Future of Time Series and Financial Analysis in the Tidyverse

答案 1 :(得分:0)

我是OP。经过一段时间的游戏后,我得到了一些我认为比我原来拥有的循环更优雅的解决方案。决定发布作为讨论的答案。仍然不会介意更优雅的东西。

使用full_df我创建了一个索引,这就是我提供给我的日子所期望的所有15分钟的时间段。

index <- data.frame(date = rep(seq(full_df$date[1], full_df$date[nrow(full_df)],by="+1 day"),each=96),
                    dec_times = rep(seq(0.25,24,0.25), length(unique(full_df$date)))
)

然后我将这个与full_df合并为两个匹配的列,因此保留了不常见的值(即我的缺失值)

index <- merge(full_df, index, by.y=c("date", "dec_times"), all.y=T)

然后我继续创建一个列,列出每个15分钟间隔属于的半小时使用plyr的{​​{1}}函数

round_any

然后我使用index$half_hour <- plyr::round_any(index$dec_times, 0.5, ceiling) 的{​​{1}}函数根据新的plyr列进行求和(利用任何事物+ NA是NA的事实)。

ddply

我相信结果数据框正是我所追求的。

half_hour

我喜欢这个解决方案

  • 无循环
  • 在数据框内工作

我不喜欢这个解决方案

  • 创建索引时的好奇心