首页 > 解决方案 > 使用基于循环计数器的参数生成循环中的函数列表以传递给 mutate_at

问题描述

我想使用mutate_at()from 将tidyverse滞后函数列表应用于一组变量。我想在循环中生成滞后函数列表,这似乎是最快/最清晰的方法。但是,不是N每次应用函数列表一次,而是mutate_at()仅应用第Nth 个函数N次。

在下面的示例中,N=2。但是,不是生成 和 的滞后 1 和 2,而是生成 和的滞后x2两次。ymutate_at()xy

我究竟做错了什么?我对更好的选择持开放态度,但我更愿意留在tidyverse.

library(tidyverse)

# I would like to use mutate_at() to take lags 1 & 2 of variables x & y.
df <- data.frame(t = 1:10, x = runif(10), y = runif(10))

# First, I generate a list of lag functions for lags 1 & 2 to pass to mutate_at()'s .funs argument.
lags <- list()
for (i in 1:2) {
    lags[[i]] <- function(x) dplyr::lag(x, n = i)
}

# Second, I add informative names to this list of lag functions.
names(lags) <- paste0('lag', str_pad(seq_along(lags), width = 2, pad = '0'))

# Third, I apply this list of lag function to x & y.
df1 <- df %>% mutate_at(vars(x, y), lags)

# However, the process above generates lag 2 of x & y twice.
df1
#>     t         x         y   x_lag01   y_lag01   x_lag02   y_lag02
#> 1   1 0.5698044 0.3292775        NA        NA        NA        NA
#> 2   2 0.6831116 0.3272847        NA        NA        NA        NA
#> 3   3 0.7219645 0.9417543 0.5698044 0.3292775 0.5698044 0.3292775
#> 4   4 0.1691243 0.7175634 0.6831116 0.3272847 0.6831116 0.3272847
#> 5   5 0.7625580 0.5500207 0.7219645 0.9417543 0.7219645 0.9417543
#> 6   6 0.1700005 0.3265627 0.1691243 0.7175634 0.1691243 0.7175634
#> 7   7 0.3595347 0.1533229 0.7625580 0.5500207 0.7625580 0.5500207
#> 8   8 0.3950479 0.6069847 0.1700005 0.3265627 0.1700005 0.3265627
#> 9   9 0.9006300 0.6709985 0.3595347 0.1533229 0.3595347 0.1533229
#> 10 10 0.9249601 0.1230972 0.3950479 0.6069847 0.3950479 0.6069847

# Here is the expected output (without the pretty names).
df2 <- df %>% mutate_at(vars(x, y), list(~ dplyr::lag(., n = 1), ~ dplyr::lag(., n = 2)))
df2
#>     t         x         y x_dplyr::lag..1 y_dplyr::lag..1 x_dplyr::lag..2
#> 1   1 0.5698044 0.3292775              NA              NA              NA
#> 2   2 0.6831116 0.3272847       0.5698044       0.3292775              NA
#> 3   3 0.7219645 0.9417543       0.6831116       0.3272847       0.5698044
#> 4   4 0.1691243 0.7175634       0.7219645       0.9417543       0.6831116
#> 5   5 0.7625580 0.5500207       0.1691243       0.7175634       0.7219645
#> 6   6 0.1700005 0.3265627       0.7625580       0.5500207       0.1691243
#> 7   7 0.3595347 0.1533229       0.1700005       0.3265627       0.7625580
#> 8   8 0.3950479 0.6069847       0.3595347       0.1533229       0.1700005
#> 9   9 0.9006300 0.6709985       0.3950479       0.6069847       0.3595347
#> 10 10 0.9249601 0.1230972       0.9006300       0.6709985       0.3950479
#>    y_dplyr::lag..2
#> 1               NA
#> 2               NA
#> 3        0.3292775
#> 4        0.3272847
#> 5        0.9417543
#> 6        0.7175634
#> 7        0.5500207
#> 8        0.3265627
#> 9        0.1533229
#> 10       0.6069847

reprex 包(v0.3.0)于 2019 年 7 月 10 日创建

标签: rdplyr

解决方案


一种更像您最初尝试的方法;问题在于您创建函数列表的方法。这里我们使用函数工厂方法:

lag_i <- function(i){
  force(i)
  function(x){
    dplyr::lag(x,i)
  }
}

lags <- list()
for (i in 1:2) {
  lags[[i]] <- lag_i(i)
}


> df %>% mutate_at(vars(x,y),lags)

   t          x          y      x_fn1      y_fn1      x_fn2      y_fn2
1   1 0.41793497 0.89151484         NA         NA         NA         NA
2   2 0.01086319 0.83059611 0.41793497 0.89151484         NA         NA
3   3 0.97040618 0.02881068 0.01086319 0.83059611 0.41793497 0.89151484
4   4 0.73283793 0.07989197 0.97040618 0.02881068 0.01086319 0.83059611
5   5 0.36587442 0.93391797 0.73283793 0.07989197 0.97040618 0.02881068
6   6 0.91053307 0.37605878 0.36587442 0.93391797 0.73283793 0.07989197
7   7 0.52912783 0.33095076 0.91053307 0.37605878 0.36587442 0.93391797
8   8 0.65377360 0.85224899 0.52912783 0.33095076 0.91053307 0.37605878
9   9 0.51129869 0.82418435 0.65377360 0.85224899 0.52912783 0.33095076
10 10 0.94932517 0.65900852 0.51129869 0.82418435 0.65377360 0.85224899

推荐阅读