我有一个显示日期,项目和值的数据框,我想添加一个列,显示其前50个条目的平均值(如果没有50,则为NA),例如表可能是
data
date item value
01/01/01 a 2
01/01/01 b 1.5
04/01/01 c 1.7
05/01/01 a 1.9
......
部分可能成为
date item value last_50_mean
........
11/09/01 a 1.2 1.1638
12/09/01 b 1.9 1.5843
12/09/01 a 1.4 1.1621
13/09/01 c 0.9 NA
........
所以在这种情况下,11/09/01之前的50个参赛作品中a的平均值是1.1638而且c在13/09/01之前没有50个参赛作品所以返回NA
我目前正在使用以下功能
执行此操作 data[, 'last_50_mean'] <- sapply(1:nrow(data), function(i){
prevDates <- data[data$date < data$date[i] & data$item == data$item[i], ]
num <- nrow(prevGames)
if(nGames >= 50){
round(mean(prevDates[(num- 49):num, ]$value), 4)
}
}
)
但是我的数据框很大并且需要很长时间(实际上我并不是100%确定它仍在运行,因为它仍在运行......有没有人知道最好的方法呢?
答案 0 :(得分:4)
N个观测值的平均值可以从累积和以及第一个和最后一个值diff(cumsum(x), lag=N - 1)
之间的差值计算得出。你的问题想要填充第一个N - 1值,所以
meanN <- function(x, N=50)
## mean of last N observations, padded in front with NA
{
x0 <- x[seq_len(length(x) - N + 1)]
x1 <- (x0 + diff(cumsum(x), lag=N-1)) / N
c(rep(NA, N - 1), x1)
}
您希望为多个群组执行此操作。对于data.frame
喜欢
df <- data.frame(item=sample(letters[1:3], 1000, TRUE),
value=runif(1000, 1, 3),
last_50_mean=NA)
这样做的一种方法是
split(df$last_50_mean, df$item) <- lapply(split(df$value, df$item), meanN)
导致例如
> tail(df)
item value last_50_mean
995 c 1.191486 2.037707
996 c 2.899214 2.073022
997 c 2.019375 2.054914
998 c 2.737043 2.066389
999 a 1.703752 1.923234
1000 c 1.602442 2.043517
这假定您的数据框按时间排序。一个潜在的问题是长向量溢出cumsum
;人们可以通过居中value
来解决这个问题,因此期望cumsum
不会偏离零。最近的一个问题涉及split<-
的替代方案,并删除了最后N个观察结果。