r-使用mutate_at重新编码多个列值,并基于管道中的突变列创建一个新列



我有一个宽格式的问卷数据数据框架,每列代表一个问卷项目。

就我个人而言,我知道如何重新编码列中的值,并根据其他列中找到的值创建新列。然而,我在尝试在一个管道中同时完成这两项工作时遇到了问题。

我的数据如下:

df <- data.frame(Q1 = c(1, 2, 1, 4), Q2 = c(4, 2, 3, 1), Q3 = c(3, 3, 2, 3),
Q4 = c(4, 4, 2, 4), Q5 = c(4, 2, 3, 1), Q6 = c(7, 2, 3, 1))

以我的样本数据集为例,我打算从列Q1、Q2和Q3中减去1,并用新的(减去的(值替换原始值。同时,我想创建一个新列,其中包含Q1、Q2和Q3的平均值,同时忽略任何NA值或3的值。

我尝试了以下代码,但Q1、Q2和Q3列没有用减去的值更新。

library(dplyr)
df$mean <- df %>%
select(Q1, Q2, Q3) %>%
mutate_all(funs(. - 1)) %>%
apply(1, function(x) {
round(mean(x[!is.na(x) & x != 3]), digits = 2)
})

我尝试过在管道中使用mutate_atmutate。但是,最终结果会删除其他未选中的列。我仍然希望其他列在最终数据集中:

df <- df %>%
select(Q1, Q2, Q3) %>%
mutate_all(funs(. - 1)) %>%
mutate(mean = apply(., 1, function(x)
round(mean(x[!is.na(x) & x != 3]), digits = 2)))

非常感谢!

我们可以定义一个要执行操作的变量向量,然后在mutate_at中使用它来执行减法。对于均值,我们可以在您已经拥有的apply中嵌套一个select,如下

subtract <- c("Q1", "Q2", "Q3")
df2 <- df %>%
mutate_at(subtract, funs(. - 1)) %>%
mutate(mean = apply(select(., one_of(subtract)), 1, function(x)
round(mean(x[!is.na(x) & x != 3]), digits = 2)))
df2
#   Q1 Q2 Q3 Q4 Q5 Q6 mean
# 1  0  3  2  4  4  7 1.00
# 2  1  1  2  4  2  2 1.33
# 3  0  2  1  2  3  3 1.00
# 4  3  0  2  4  1  1 1.00

一种选择是,我们select是所需的列,并从每个列中减去-1,然后从这些列中取meanrowwise并添加新列。

library(tidyverse)
df %>%
select(1:3) %>%
mutate_all(funs(. - 1)) %>%
rowwise() %>%
do( (.) %>% as.data.frame %>% 
mutate(mean = mean(.[. != 3], na.rm = TRUE)))
#    Q1    Q2    Q3  mean
#* <dbl> <dbl> <dbl> <dbl>
#1  0     3.00  2.00  1.00
#2  1.00  1.00  2.00  1.33
#3  0     2.00  1.00  1.00
#4  3.00  0     2.00  1.00

也可以写成

(df[1:3] - 1) %>%
rowwise() %>%
do( (.) %>% as.data.frame %>% 
mutate(mean = mean(.[. != 3], na.rm = TRUE)))

或者,为了完全避免do调用,我们可以创建一个计算mean并应用它的函数rowwise

apply_fun <- function(x) {
mean(x[x != 3], na.rm = TRUE)
}
(df[1:3] - 1) %>%
rowwise() %>%
mutate(mean = apply_fun(c(Q1, Q2, Q3)))
#    Q1    Q2    Q3  mean
#  <dbl> <dbl> <dbl> <dbl>
#1  0     3.00  2.00  1.00
#2  1.00  1.00  2.00  1.33
#3  0     2.00  1.00  1.00
#4  3.00  0     2.00  1.00

最新更新