【发布时间】:2016-05-04 07:54:33
【问题描述】:
我有一个数据框,其中包含多个日期(时间)的银行资产。每家银行都有一个唯一的 ID:
# Sample Data
time <- c(51, 52, 53, 55, 56, 51, 52, 51, 52, 53)
id <- c(1234, 1234, 1234, 1234, 1234, 2345, 2345, 3456, 3456, 3456)
name <- c("BANK A", "BANK A", "BANK A", "BANK A", "BANK A", "BANK B", "BANK B", "BANK C",
"BANK C", "BANK C")
assets <- c(5000, 6000, 4000, 7000, 8000, 10000, 12000, 30000, 35000, 40000)
df <- data.frame(time, id, name, assets)
> df
time id name assets
1 51 1234 BANK A 5000
2 52 1234 BANK A 6000
3 53 1234 BANK A 4000
4 55 1234 BANK A 7000
5 56 1234 BANK A 8000
6 51 2345 BANK B 10000
7 52 2345 BANK B 12000
8 51 3456 BANK C 30000
9 52 3456 BANK C 35000
10 53 3456 BANK C 40000
对于每家银行,我想计算资产的滚动平均值,根据连续时间值的数量改变宽度。因此,滚动平均值应包括银行资产的所有可用连续先前值。如果一家银行没有可用的先前价值,则它应等于资产。因此,我添加了一个计算连续时间值数量的列,而不是使用 zoo 包中的rollapplyr,这给了我想要的结果,但是对于大型数据集,它太慢了:
# Calculate number of consecutive times
require(dplyr)
df <- df %>%
mutate(number.time = 1) %>% # insert column for number.time, start value = 1
group_by(id) %>%
arrange(time) # correct order for moving average
for(i in 2:nrow(df)) # Start loop in second row, end in last row of df
df$number.time[i] <-
ifelse(df$time[i] == df$time[i-1]+1, # Is time consecutive?
df$number.time[i - 1] + 1, # If yes: add 1 to previous number.time
1) # If no: set number.time = 1
# Moving Average
require(zoo)
df %>%
mutate(mov.average = rollapplyr(data = assets,
width = number.time, # use number.time for width
FUN = mean,
fill = NA,
na.rm = TRUE))
Source: local data frame [10 x 6]
Groups: id [3]
time id name assets number.time mov.average
(dbl) (dbl) (fctr) (dbl) (dbl) (dbl)
1 51 1234 BANK A 5000 1 5000
2 52 1234 BANK A 6000 2 5500
3 53 1234 BANK A 4000 3 5000
4 55 1234 BANK A 7000 1 7000
5 56 1234 BANK A 8000 2 7500
6 51 2345 BANK B 10000 1 10000
7 52 2345 BANK B 12000 2 11000
8 51 3456 BANK C 30000 1 30000
9 52 3456 BANK C 35000 2 32500
10 53 3456 BANK C 40000 3 35000
如何使用更快的函数获得此输出?我知道来自动物园的rollmean 以及来自TTR 的SMA 和来自预测的ma,但这些都不允许改变宽度。我的问题也可能与this question和这个rblog有关,但是我对C++不熟悉,对函数编写也不太了解,所以我不太了解那些帖子。
编辑 1:请注意,在我上面的代码中,它不是 for-loop,而是 rollapplyr,它需要很多时间。
编辑 2: 滚动平均值应包含不超过最后 4 个值。也就是说,根据时间变量,连续值的数量与连续值一样多,但不超过最后 4 个值。抱歉问题不准确! :/ 我的措辞基于使用“number.time”列的假设,其中很容易将所有值限制为最大值 = 4。
【问题讨论】:
-
您可能需要通过 (1)
id和 (2)ave(df$time, df$id, FUN = function(x) cumsum(c(TRUE, (x[-1] - x[-length(x)]) != 1)))申请cumsum(assets) / seq_along(assets) -
这很完美,当然速度也很快。不幸的是,我注意到我的问题是不准确的:我想计算不超过最后 4 个值的平均平均值,这与最后 4 个值一样多,但不超过最后 4 个值。您是否认为有可能将此限制实施到您的代码中?我上面的问题是基于我将使用列“number.time”的假设,以便我可以简单地将其限制为 4,对此感到抱歉......:/
标签: r time-series zoo data-manipulation windowing