首页 > 解决方案 > 面板数据的滚动平均值(有一些细节)

问题描述

我想出了一些代码来计算面板数据的滚动平均值(数据中的一行包含一天中一个主题的值)。由于我有一些更具体的要求,代码变得相当复杂。在我看来,对于一个不太罕见的应用程序来说太复杂了。

这是我需要的:

  1. 滚动平均值((a)前 3 天的值的平均值,不包括“当前”日期,(b)仅当此窗口中至少有 2 个非缺失值时才计算)

  2. 尊重面板结构

不会太复杂吧?

对于 1. 我决定使用rollapplyr()andmean( , na.rm = T)来排除当前日期 (a) 我决定使用自制的滞后函数,对于 (b) 一个 if 语句。而对于 2. 我把所有东西都包裹在一个tapply()(withunlist() ) 中,以尊重面板结构。

这是代码示例:

library(zoo)

# example data (with missings)
set.seed(1)
df = data.frame(subject = rep(c("a", "b"), each = 10), day = rep(1:10, 2), value = rnorm(20))
df$value[15:17] = NA

# lag function (sensitive to "single day" subjects)
lag <- function(x, l = 1) { 
  if (length(x) > 1) (c(rep(NA, l), x[1:(length(x)-l)])) else (NA) 
} 

# calculate rolling mean
df$roll_mean3 = unlist(tapply(df$value, df$subject, 
                              FUN = function(x) lag(rollapplyr(x, width = 3, fill = NA, partial = T,
                                                               FUN = function(x) ifelse(sum(!is.na(x)) > 1, mean(x, na.rm = T), NA)))))
df

正如我所说,对于我认为并不遥远的情况,这个解决方案似乎过于复杂。

您对如何以更简单(不易出错)的方式执行此操作有建议吗?我是否错过了一些可以更轻松地处理面板数据的基本功能?

为了说明,我的代码的输出是:

   subject day      value   roll_mean3
1        a   1 -0.6264538           NA
2        a   2  0.1836433           NA
3        a   3 -0.8356286 -0.221405243
4        a   4  1.5952808 -0.426146366
5        a   5  0.3295078  0.314431838
6        a   6 -0.8204684  0.363053321
7        a   7  0.4874291  0.368106730
8        a   8  0.7383247 -0.001177187
9        a   9  0.5757814  0.135095124
10       a  10 -0.3053884  0.600511703
11       b   1  1.5117812           NA
12       b   2  0.3898432           NA
13       b   3 -0.6212406  0.950812202
14       b   4 -2.2146999  0.426794608
15       b   5         NA -0.815365744
16       b   6         NA -1.417970234
17       b   7         NA           NA
18       b   8  0.9438362           NA
19       b   9  0.8212212           NA
20       b  10  0.5939013  0.882528703

标签: rlagmoving-averagepanel-datatapply

解决方案


用于在每个主题上单独ave运行。rollapply然后在使用时rollapply请注意,它width可以是一个包含偏移向量(或多个向量)的列表,因此list(-seq(3))意味着前 3 个元素。有关?rollapply参数的更多信息,请参阅。

Mean <- function(x) if (sum(!is.na(x)) >= 2) mean(x, na.rm = TRUE) else NA
roll <- function(x)  rollapply(x, list(-seq(3)), Mean, fill = NA, partial = TRUE)
transform(df, roll = ave(value, subject, FUN = roll))

推荐阅读