通过 tidyverse 使用粘贴和数字索引按列应用函数

Applying a function column-wise using paste and a numeric index via the tidyverse

我需要能够根据定制的列名称列表将转换函数应用于一系列列。每个列名都有相同的前缀和数字后缀,所以我希望找到一种简单的方法来使用 tidyverse 中的这些后缀来转换每个列。

这是一些玩具数据。

rm(list = ls())
set.seed(1)
df <- data.frame(q1 = sample(1:5, 10, replace = T),
                 q2 = sample(1:3, 10, replace = T),
                 q3 = sample(1:6, 10, replace = T),
                 q4 = sample(1:5, 10, replace = T),
                 q5 = sample(1:5, 10, replace = T))

#    q1 q2 q3 q4 q5
# 1   1  1  5  4  4
# 2   4  1  1  1  1
# 3   1  2  1  4  1
# 4   2  2  6  3  4
# 5   5  2  5  2  1
# 6   3  2  5  2  2
# 7   2  3  2  4  3
# 8   3  1  2  4  2
# 9   3  3  6  4  2
# 10  1  1  1  2  5

现在说 q1q4q5 都需要相同的重新编码。使用每个变量的数字后缀,我可以使用 base R 中的以下 for 循环和 plyr

中的 mapvalues 函数对它们进行重新编码
vec1 <- c(1, 4, 5)
df1 <- df
for (i in vec1) {
  df1[,paste0("q",i)] <- plyr::mapvalues(df1[,paste0("q",i)], from = 1:5, to = seq(100,0,-25))
}
df1

#     q1 q2 q3  q4  q5
# 1  100  1  5  25  25
# 2   25  1  1 100 100
# 3  100  2  1  25 100
# 4   75  2  6  50  25
# 5    0  2  5  75 100
# 6   50  2  5  75  75
# 7   75  3  2  25  50
# 8   50  1  2  25  75
# 9   50  3  6  25  75
# 10 100  1  1  75   0

我也可以很容易地使用 dplyr 重新编码单个列。

df %>% mutate(q1 = dplyr::recode(q1, `1` = 100, `2` = 75, `3` = 50, `4` = 25, `5` = 0))

#     q1 q2 q3 q4 q5
# 1  100  1  5  4  4
# 2   25  1  1  1  1
# 3  100  2  1  4  1
# 4   75  2  6  3  4
# 5    0  2  5  2  1
# 6   50  2  5  2  2
# 7   75  3  2  4  3
# 8   50  1  2  4  2
# 9   50  3  6  4  2
# 10 100  1  1  2  5

但是当我尝试在 dplyr 中使用 for 循环执行此操作时,我 运行 遇到了各种各样的问题。基于 post 我尝试使用 rlang::syms()!!! 函数

df2 <- df
for (i in 1:length(vec1)) {
  var <- rlang::syms(paste0("q", vec1[i]))
  df2 <- df2 %>% mutate(!!!var = dplyr::recode(!!!var, `1` = 100, `2` = 75, `3` = 50, `4` = 25, `5` = 0))
}

但它会产生错误

Error: unexpected '=' in:
"  var <- rlang::syms(paste0("q", vec1[i]))
  df2 <- df2 %>% mutate(!!!var ="

有什么建议吗?不必是 dplyr。我感觉 purrr 可能有一些答案,但我对此几乎一无所知。

我们可以在新 dplyr 中使用 mutate_atacross 将相同的功能应用于多个列。

library(dplyr)
df %>%
  mutate(across(vec1, recode, `1` = 100, `2` = 75, `3` = 50, `4` = 25, `5` = 0))
  #mutate_at(vec1, recode, `1` = 100, `2` = 75, `3` = 50, `4` = 25, `5` = 0)

#    q1 q2 q3  q4  q5
#1  100  1  5  25  25
#2   25  1  1 100 100
#3  100  2  1  25 100
#4   75  2  6  50  25
#5    0  2  5  75 100
#6   50  2  5  75  75
#7   75  3  2  25  50
#8   50  1  2  25  75
#9   50  3  6  25  75
#10 100  1  1  75   0