通过 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
现在说 q1
、q4
和 q5
都需要相同的重新编码。使用每个变量的数字后缀,我可以使用 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_at
或 across
将相同的功能应用于多个列。
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
我需要能够根据定制的列名称列表将转换函数应用于一系列列。每个列名都有相同的前缀和数字后缀,所以我希望找到一种简单的方法来使用 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
现在说 q1
、q4
和 q5
都需要相同的重新编码。使用每个变量的数字后缀,我可以使用 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 循环执行此操作时,我 运行 遇到了各种各样的问题。基于 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_at
或 across
将相同的功能应用于多个列。
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