计算均值偏差值(从这一列中减去除一列之外的所有列的平均值)

Calculate mean-deviated values (subtract mean of all columns except one from this one column)

我有一个具有以下结构的数据集:

df <- data.frame(id = 1:5,
                 study = c("st1","st2","st3","st4","st5"),
                 a_var = c(10,20,30,40,50),
                 b_var = c(6,5,4,3,2),
                 c_var = c(3,4,5,6,7),
                 d_var = c(80,70,60,50,40))

我想计算名称中包含 _var 的每个列与名称中包含 _var 的所有其他列的平均值之间的差异,如下所示:

mean_deviated_value <- function(data, variable) {
  md_value = data[,variable] - rowMeans(data[,names(data) != variable])
  md_value
  }
    
df$a_var_md <- mean_deviated_value(dplyr::select(df, contains("_var")), "a_var")
df$b_var_md <- mean_deviated_value(dplyr::select(df, contains("_var")), "b_var")
df$c_var_md <- mean_deviated_value(dplyr::select(df, contains("_var")), "c_var")
df$d_var_md <- mean_deviated_value(dplyr::select(df, contains("_var")), "d_var")

这给了我想要的输出:

  id study a_var b_var c_var d_var   a_var_md  b_var_md c_var_md d_var_md
1  1   st1    10     6     3    80 -19.666667 -12.33333    -9.80 83.80000
2  2   st2    20     5     4    70  -6.333333 -16.91667   -10.35 70.76667
3  3   st3    30     4     5    60   7.000000 -21.50000   -10.90 57.73333
4  4   st4    40     3     6    50  20.333333 -26.08333   -11.45 44.70000
5  5   st5    50     2     7    40  33.666667 -30.66667   -12.00 31.66667

如何一次完成,不重复代码,最好用dplyr/purrr?

我试过这个:

df %>%
  mutate(across(contains("_var"), ~ list(md = .x - rowMeans(select(., contains("_var") & !.x)))))

并得到这个错误:

Error: Problem with `mutate()` input `..1`.
ℹ `..1 = across(...)`.
x no applicable method for 'select' applied to an object of class "c('double', 'numeric')"

我们可以使用 map_dfctransmute 来创建 *_md 列,并使用 glue syntax 作为名称。

library(tidyverse)

nms <- names(df) %>%
        str_subset('^.*_')

bind_cols(df, map_dfc(nms, ~transmute(df, '{.x}_md' := mean_deviated_value(select(df, contains("_var")), .x))))
#>   id study a_var b_var c_var d_var   a_var_md  b_var_md  c_var_md d_var_md
#> 1  1   st1    10     6     3    80 -19.666667 -25.00000 -29.00000 73.66667
#> 2  2   st2    20     5     4    70  -6.333333 -26.33333 -27.66667 60.33333
#> 3  3   st3    30     4     5    60   7.000000 -27.66667 -26.33333 47.00000
#> 4  4   st4    40     3     6    50  20.333333 -29.00000 -25.00000 33.66667
#> 5  5   st5    50     2     7    40  33.666667 -30.33333 -23.66667 20.33333

请注意,如果您使用赋值。第一次 rowMeans 将与 b_varc_bard_bar 一起计算。但是第二次,contains("_var") 还将捕获之前创建的 a_var_md 并使用它来计算均值。我不知道这是否是预期的行为,但值得一提。

df$a_var_md <- mean_deviated_value(dplyr::select(df, contains("_var")), "a_var")
select(df, contains("_var"))
#>   a_var b_var c_var d_var   a_var_md
#> 1    10     6     3    80 -19.666667
#> 2    20     5     4    70  -6.333333
#> 3    30     4     5    60   7.000000
#> 4    40     3     6    50  20.333333
#> 5    50     2     7    40  33.666667

我们可以通过将 contains("_var") 替换为 matches("^.*_var$")

来避免这种情况

reprex package (v2.0.1)

于 2021-12-20 创建