【问题标题】:use dplyr::mutate() to get rolling mean over selected columns使用 dplyr::mutate() 获取选定列的滚动平均值
【发布时间】:2021-01-04 13:55:04
【问题描述】:

我想使用 dplyr 获取新列中每最后 2 行的滚动平均值。让我们以 mtcars 作为示例数据。 我会将行名转换为新列,以更好地代表我的真实数据集(第一列中有日期)

df = tibble::rownames_to_column(mtcars, "exclude")

现在我想要一个新列,它给出每最后 2 行的滚动平均值(假设现在包含汽车名称的“排除”列实际上包含日期)。应该是输出:

我尝试使用 dplyr::mutate() 和 cross() 来做到这一点,但我没有成功。

更重要的是,有时我可能必须为之前的许多行计算这些滚动行均值,比如 13 左右。

感谢和祝福!

【问题讨论】:

  • rolling_mean 属于哪一列?
  • 在行上(即结果在“新列”下的图片中)

标签: r select dplyr rolling-computation


【解决方案1】:

您可以取除第一列之外的所有列的逐行平均值,并将两个值的滚动平均值添加为新列。在基础 R 中,您可以这样做:

val <- rowMeans(df[-1])
df$new_column <- c(NA, (head(val, -1) + tail(val, -1))/2)

如果你想使用dplyr,你可以使用:

library(dplyr)

df %>%
  mutate(new_column = rowMeans(.[-1]), 
         new_column = (new_column + lag(new_column))/2)


#              exclude  mpg cyl  disp  hp drat   wt qsec vs am gear carb new_column
#1            Mazda RX4 21.0   6 160.0 110 3.90 2.62 16.5  0  1    4    4         NA
#2        Mazda RX4 Wag 21.0   6 160.0 110 3.90 2.88 17.0  0  1    4    4       29.9
#3           Datsun 710 22.8   4 108.0  93 3.85 2.32 18.6  1  1    4    1       26.8
#4       Hornet 4 Drive 21.4   6 258.0 110 3.08 3.21 19.4  1  0    3    1       31.2
#5    Hornet Sportabout 18.7   8 360.0 175 3.15 3.44 17.0  0  0    3    2       46.2
#6              Valiant 18.1   6 225.0 105 2.76 3.46 20.2  1  0    3    1       44.4
#7           Duster 360 14.3   8 360.0 245 3.21 3.57 15.8  0  0    3    4       47.4
#8            Merc 240D 24.4   4 146.7  62 3.69 3.19 20.0  1  0    4    2       42.2
#...
#...

如果您以长格式获取数据以找到回溯 x 天数的解决方案会更容易。

x <- 2
df %>% mutate(row = row_number()) -> df1

df1 %>%
  tidyr::pivot_longer(cols = -c(exclude, row)) %>%
  group_by(row) %>%
  summarise(val = mean(value)) %>%
  mutate(val = zoo::rollmeanr(val, x, fill = NA)) %>%
  left_join(df1, by = 'row')

【讨论】:

  • 我喜欢你的第二个回答。但是,如果我们想要过去 13 天的滚动平均值怎么办。我试过: mutate(new_column= rollapply(.[-1],13,mean,partial=FALSE,fill=NA,align="right")) 可以工作,但给出一个列表作为结果而不是向量
  • 我尝试了与您在先排除行号然后加入它们时所做的类似的事情,但是我通常不喜欢以这种方式编码,而是更喜欢在一个数据框中完成所有操作
【解决方案2】:

使用dplyr 你可以做到

df$new <- df %>% mutate(id1 = row_number()) %>% left_join(df %>% mutate(id1 = row_number()+1), by = "id1") %>% 
  select(-exclude.y, -exclude.x, -id1) %>%
  rowMeans()

> df
               exclude  mpg cyl  disp  hp drat    wt  qsec vs am gear carb      new
1            Mazda RX4 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4       NA
2        Mazda RX4 Wag 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 29.94432
3           Datsun 710 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1 26.78977
4       Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 31.16886
5    Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2 46.20205
6              Valiant 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1 44.35682
7           Duster 360 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4 47.38455
8            Merc 240D 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2 42.17727
9             Merc 230 22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2 25.93409
10            Merc 280 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4 29.54682
11           Merc 280C 17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4 31.82364
12          Merc 450SE 16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3 39.10909
13          Merc 450SL 17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3 46.46545
14         Merc 450SLC 15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3 46.42500
15  Cadillac Fleetwood 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4 56.29136
16 Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4 66.14564
17   Chrysler Imperial 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4 66.01541
18            Fiat 128 32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1 42.70659
19         Honda Civic 30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2 18.59159
20      Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1 18.27818
21       Toyota Corona 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1 21.85136
22    Dodge Challenger 15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2 36.06477
23         AMC Javelin 15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2 46.62432
24          Camaro Z28 13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4 52.38023
25    Pontiac Firebird 19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2 58.06614
26           Fiat X1-9 27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1 38.15409
27       Porsche 914-2 26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2 21.85386
28        Lotus Europa 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2 24.82968
29      Ford Pantera L 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4 42.92605
30        Ferrari Dino 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6 47.74000
31       Maserati Bora 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8 48.83182
32          Volvo 142E 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2 44.70909

对于param 足够大的数字

library(zoo)
df$new <- df %>% select(-exclude) %>% rowMeans()
param <- 13
df$new <- rollmeanr(df$new, param, fill=NA)


> df
               exclude  mpg cyl  disp  hp drat    wt  qsec vs am gear carb      new
1            Mazda RX4 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4       NA
2        Mazda RX4 Wag 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4       NA
3           Datsun 710 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1       NA
4       Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1       NA
5    Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2       NA
6              Valiant 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1       NA
7           Duster 360 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4       NA
8            Merc 240D 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2       NA
9             Merc 230 22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2       NA
10            Merc 280 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4       NA
11           Merc 280C 17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4       NA
12          Merc 450SE 16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3       NA
13          Merc 450SL 17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3 36.85434
14         Merc 450SLC 15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3 38.11916
15  Cadillac Fleetwood 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4 40.90773
16 Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4 44.17391
17   Chrysler Imperial 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4 46.26873
18            Fiat 128 32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1 43.63615
19         Honda Civic 30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2 42.30485
20      Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1 39.15824
21       Toyota Corona 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1 39.17779
22    Dodge Challenger 15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2 40.71681
23         AMC Javelin 15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2 41.80510
24          Camaro Z28 13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4 43.87936
25    Pontiac Firebird 19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2 44.72157
26           Fiat X1-9 27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1 42.60069
27       Porsche 914-2 26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2 40.94139
28        Lotus Europa 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2 37.76043
29      Ford Pantera L 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4 37.36915
30        Ferrari Dino 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6 34.94883
31       Maserati Bora 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8 38.31149
32          Volvo 142E 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2 38.96691

第二种解决方案基于您在任何行中都没有任何NA 的假设。让我们检查一个简单的数据

df <- data.frame(col1 = LETTERS,
                 col2 = 1,
                 col3 = 1:26,
                 col4 = 2:27)
df[2,2] <- NA

df
> df
   col1 col2 col3 col4
1     A    1    1    2
2     B   NA    2    3
3     C    1    3    4
4     D    1    4    5
5     E    1    5    6
6     F    1    6    7
7     G    1    7    8
8     H    1    8    9
9     I    1    9   10
10    J    1   10   11
11    K    1   11   12
12    L    1   12   13
13    M    1   13   14
14    N    1   14   15
15    O    1   15   16
16    P    1   16   17
17    Q    1   17   18
18    R    1   18   19
19    S    1   19   20
20    T    1   20   21
21    U    1   21   22
22    V    1   22   23
23    W    1   23   24
24    X    1   24   25
25    Y    1   25   26
26    Z    1   26   27

现在是计算部分


df$new <- df %>% select(-col1) %>% rowMeans(na.rm = TRUE)
param <- 2
df$new <- rollmeanr(df$new, param, fill=NA)

   col1 col2 col3 col4       new
1     A    1    1    2        NA
2     B   NA    2    3  1.916667
3     C    1    3    4  2.583333
4     D    1    4    5  3.000000
5     E    1    5    6  3.666667
6     F    1    6    7  4.333333
7     G    1    7    8  5.000000
8     H    1    8    9  5.666667
9     I    1    9   10  6.333333
10    J    1   10   11  7.000000
11    K    1   11   12  7.666667
12    L    1   12   13  8.333333
13    M    1   13   14  9.000000
14    N    1   14   15  9.666667
15    O    1   15   16 10.333333
16    P    1   16   17 11.000000
17    Q    1   17   18 11.666667
18    R    1   18   19 12.333333
19    S    1   19   20 13.000000
20    T    1   20   21 13.666667
21    U    1   21   22 14.333333
22    V    1   22   23 15.000000
23    W    1   23   24 15.666667
24    X    1   24   25 16.333333
25    Y    1   25   26 17.000000
26    Z    1   26   27 17.666667

现在检查第二行。它是 [(1+1+2)/3 + (2+3)/2]/2 = 1.916 而它应该是 1+1+2+2+3/5 = 1.800。罗纳克的回答也是如此。现在这取决于您实际想要什么。如果您希望它计算数学上正确的第二种方式,请发表评论。

【讨论】:

  • 但是如果我们想要一个 13 天的滚动窗口呢?将“+1”改为“+13”似乎不正确吧?
  • 我的意思是现在我们做了一个 2 行滚动平均值,但是如果我们想将滚动平均值的窗口更改为 13 怎么办。我们应该如何在您的代码中应用它?
  • 但是@JelleJansen,这个滚动计算(这个和 Ronak 提出的那个)是基于均值的,因此如果任何行元素是 NA 任何地方都可能不会给出预期的结果。在这种情况下,将不得不采用不同的策略。在df[2,5] &lt;- NA 之后尝试此代码并检查。这就是为什么我之前提出了join的问题。
  • 所以如果我没看错的话,我们似乎还没有合适的解决方案。我在 dplyr 的其他示例中使用 rollapply 来解决问题。可惜的是,在宽格式数据帧中的 mutate() 中使用 rollapply 时,我不知道如何省略第一列
  • 没有。这取决于预期的结果。如果您想要实际平均值(而不是平均值),您可以使用计数非 NA/null 值并同时使用 rowSums。此后,您可以结合 rowSums 和 count 来计算实际平均值
【解决方案3】:

最后我将它转换为 xts 格式,这样我就可以在数据集上使用 rollapply 而不必担心日期列。

【讨论】:

    猜你喜欢
    • 2018-10-25
    • 2014-11-29
    • 2019-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-11
    相关资源
    最近更新 更多