对 R 中的所有列按年份应用 运行 平均值

Apply running average by year for all columns in R

我需要计算每列的 运行 年平均值。我的数据示例:

dat <- data.frame(yr = c(1980, 1980, 1980, 1980, 1980, 1981, 1981, 1981, 1981, 1981, 1982, 1982, 1982, 1982, 1982), data1 = c(-10.16,  -7.48,  -3.31,  -6.04, -11.68, -13.40, -10.41, -10.65,  -6.70, -17.05, -25.62, -29.14, -16.65,  -6.42,   0.28), data2 = c(2.30, -7.52, -13.26, -13.24, -14.74,  -9.38,  -8.93, -11.78, -14.07, -11.66,  -8.82, -10.30,  -7.99, -10.02, -15.36), data3 = c(-14.83, -15.08, -16.44, -18.95, -13.40,  -7.16, -4.35,  -1.61,  -0.01,  -0.35,  -2.09,  -3.12,   0.87,  -0.06,   2.29))

运行 平均值计算如下:

library(TTR)
library(dplyr)
runavg <- with(dat, ave(data1, yr, FUN=function(x) 
    TTR::runMean(x, n=3)) )

问题很简单,但我想请你更详细地解释一下如何将这段代码应用到每一列?我尝试了使用 lapply、函数、变异的各种解决方案...我刚刚意识到我在这方面的知识不够:(。我将非常感谢您的帮助。

我们可以在 tidyverse 中使用 across 遍历所有 'data' 列并通过应用 runMean 函数

创建新列
library(dplyr)
library(TTR)
dat <- dat %>% 
   group_by(yr) %>%
     mutate(across(starts_with('data'),
      ~ runMean(., n = 3), .names = 'runavg_{.col}'))

-输出

dat
# A tibble: 15 × 7
# Groups:   yr [3]
      yr  data1  data2  data3 runavg_data1 runavg_data2 runavg_data3
   <dbl>  <dbl>  <dbl>  <dbl>        <dbl>        <dbl>        <dbl>
 1  1980 -10.2    2.3  -14.8         NA           NA          NA    
 2  1980  -7.48  -7.52 -15.1         NA           NA          NA    
 3  1980  -3.31 -13.3  -16.4         -6.98        -6.16      -15.4  
 4  1980  -6.04 -13.2  -19.0         -5.61       -11.3       -16.8  
 5  1980 -11.7  -14.7  -13.4         -7.01       -13.7       -16.3  
 6  1981 -13.4   -9.38  -7.16        NA           NA          NA    
 7  1981 -10.4   -8.93  -4.35        NA           NA          NA    
 8  1981 -10.6  -11.8   -1.61       -11.5        -10.0        -4.37 
 9  1981  -6.7  -14.1   -0.01        -9.25       -11.6        -1.99 
10  1981 -17.0  -11.7   -0.35       -11.5        -12.5        -0.657
11  1982 -25.6   -8.82  -2.09        NA           NA          NA    
12  1982 -29.1  -10.3   -3.12        NA           NA          NA    
13  1982 -16.6   -7.99   0.87       -23.8         -9.04       -1.45 
14  1982  -6.42 -10.0   -0.06       -17.4         -9.44       -0.77 
15  1982   0.28 -15.4    2.29        -7.60       -11.1         1.03 

base R中类似的选项是lapply

dat[paste0('runavg_', names(dat)[-1])] <- lapply(dat[-1], function(x) ave(x, dat$yr, FUN = function(u) runMean(u,  n = 3)))

1) 这使用了 zoo 中的 rollmeanr,也使用了来自 base R 的 by。rollmeanr 可以一次处理多个列,提供了一些简化。这会将 dat[-1] 拆分为 dat[[1]],即按年份拆分,然后将 rollmeanr 应用于每个组件。然后我们将组件重新绑定在一起,并将原始数据绑定到它。

library(zoo)

avg <- do.call("rbind", by(dat[-1], dat[[1]], rollmeanr, 3, fill = NA))
cbind(dat, avg = avg)

给予:

     yr  data1  data2  data3  avg.data1  avg.data2   avg.data3
1  1980 -10.16   2.30 -14.83         NA         NA          NA
2  1980  -7.48  -7.52 -15.08         NA         NA          NA
3  1980  -3.31 -13.26 -16.44  -6.983333  -6.160000 -15.4500000
4  1980  -6.04 -13.24 -18.95  -5.610000 -11.340000 -16.8233333
5  1980 -11.68 -14.74 -13.40  -7.010000 -13.746667 -16.2633333
6  1981 -13.40  -9.38  -7.16         NA         NA          NA
7  1981 -10.41  -8.93  -4.35         NA         NA          NA
8  1981 -10.65 -11.78  -1.61 -11.486667 -10.030000  -4.3733333
9  1981  -6.70 -14.07  -0.01  -9.253333 -11.593333  -1.9900000
10 1981 -17.05 -11.66  -0.35 -11.466667 -12.503333  -0.6566667
11 1982 -25.62  -8.82  -2.09         NA         NA          NA
12 1982 -29.14 -10.30  -3.12         NA         NA          NA
13 1982 -16.65  -7.99   0.87 -23.803333  -9.036667  -1.4466667
14 1982  -6.42 -10.02  -0.06 -17.403333  -9.436667  -0.7700000
15 1982   0.28 -15.36   2.29  -7.596667 -11.123333   1.0333333

1a) 另一种可能性是定义您自己的 Mean 函数,如果年份都相同则取平均值,否则取 returns NA。可以与 rollapplyr 一起使用。

library(zoo)

Mean <- function(x) if (var(x[, 1]) == 0) colMeans(x[, -1]) else NA
data.frame(dat, avg = rollapplyr(dat, 3, Mean, fill = NA, by.column = FALSE))

2) 使用 dplyr 和 zoo 我们可以像这样使用 group_by 和 group_modify。 group_modify 函数每年运行 rollmeanr。

library(dplyr, exclude = c("lag", "filter"))
library(zoo)

dat %>%
  group_by(yr) %>%
  group_modify(~ data.frame(., avg = rollmeanr(., 3, fill = NA)) ) %>%
  ungroup