我有一个宽格式的问卷数据数据框架,每列代表一个问卷项目。
就我个人而言,我知道如何重新编码列中的值,并根据其他列中找到的值创建新列。然而,我在尝试在一个管道中同时完成这两项工作时遇到了问题。
我的数据如下:
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_at
和mutate
。但是,最终结果会删除其他未选中的列。我仍然希望其他列在最终数据集中:
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,然后从这些列中取mean
、rowwise
并添加新列。
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