rowSums 在不修改基础数据帧的情况下排除 dplyr 管道中的特定值
rowSums excluding a particular value in a dplyr pipe without modifying the underlying data frame
我有一个宽格式问卷数据的数据框,每一列代表一个问卷项目。
数据如下所示:
df <- data.frame(Q1 = c(1, 4, 2, 3, 1, 1, 4, 4, 1, 2),
Q2 = c(NA, 3, 1, 4, NA, NA, 3, 4, 1, 2),
Q3 = c(3, 4, 1, 2, 4, NA, NA, 1, 1, 2),
Q4 = c(NA, 4, 1, 1, 1, 3, NA, 2, 2, NA))
我想使用 rowSums
函数对每行中不是“4”的值求和并排除 NA 并将结果除以非 4 和非 NA 的数量列(使用 dplyr 管道)。我不想替换底层数据框中的 4s;我想保持原样。
因为我不知道如何将结果除以非 4 列和非 NA 列的数量,所以我只尝试尝试问题的第一部分。我已经使用以下代码尝试了第一部分,但没有成功:
library(dplyr)
df <- df %>%
as.data.frame() %>%
mutate(sum = rowSums(.[. != 4, ], na.rm = TRUE))
所需的输出如下所示:
在上面的屏幕截图中,"mean" 列是非 4 和非 NA 值的总和除以非 4 和非 NA 列的数量。
谢谢!
如果我们想在 dplyr
中严格执行此操作,我们可以将 rowwise
与 do
一起使用,并计算每行不为 4 的值的总和,然后将它们除以 length
的值。
library(dplyr)
df %>%
rowwise() %>%
do( (.) %>% as.data.frame %>%
mutate(mean = sum(.[. != 4], na.rm = TRUE)/length(.[.!=4 & !is.na(.)])))
# Q1 Q2 Q3 Q4 mean
# * <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 1.00 NA 3.00 NA 2.00
# 2 4.00 3.00 4.00 4.00 3.00
# 3 2.00 1.00 1.00 1.00 1.25
# 4 3.00 4.00 2.00 1.00 2.00
# 5 1.00 NA 4.00 1.00 1.00
# 6 1.00 NA NA 3.00 2.00
# 7 4.00 3.00 NA NA 3.00
# 8 4.00 4.00 1.00 2.00 1.50
# 9 1.00 1.00 1.00 2.00 1.25
#10 2.00 2.00 2.00 NA 2.00
EDIT - 在发布答案后,现在我意识到我们实际上可以使用 mean
df %>%
rowwise() %>%
do( (.) %>% as.data.frame %>%
mutate(mean = mean(.[. != 4], na.rm = TRUE)))
sp_mean <- function(x) mean(x[!is.na(x) & x != 4])
df$mean <-
df %>%
apply(1, sp_mean)
df
Q1 Q2 Q3 Q4 mean
1 1 NA 3 NA 2.00
2 4 3 4 4 3.00
3 2 1 1 1 1.25
4 3 4 2 1 2.00
5 1 NA 4 1 1.00
6 1 NA NA 3 2.00
7 4 3 NA NA 3.00
8 4 4 1 2 1.50
9 1 1 1 2 1.25
10 2 2 2 NA 2.00
编辑 1 - 稍微更健壮:
df$mean <-
df %>%
select(matches("^Q\d+")) %>%
apply(1, sp_mean)
matches("^Q\d+")
匹配以 Q1, Q2,..., Q199, Q200, ...
开头的列名
编辑 2 -
将我的 sp_mean() 与 Ronak 的解决方案相结合(不需要 do() 吗?):
df %>%
rowwise() %>%
mutate(mean = sp_mean(c(Q1, Q2, Q3, Q4)))
使用 base R 你可以做:
df$mean = rowMeans(`is.na<-`(df,df==4),T)#or rowMeans(replace(df,df==4,NA),T)
> df
Q1 Q2 Q3 Q4 mean
1 1 NA 3 NA 2.00
2 4 3 4 4 3.00
3 2 1 1 1 1.25
4 3 4 2 1 2.00
5 1 NA 4 1 1.00
6 1 NA NA 3 2.00
7 4 3 NA NA 3.00
8 4 4 1 2 1.50
9 1 1 1 2 1.25
10 2 2 2 NA 2.00
我有一个宽格式问卷数据的数据框,每一列代表一个问卷项目。
数据如下所示:
df <- data.frame(Q1 = c(1, 4, 2, 3, 1, 1, 4, 4, 1, 2),
Q2 = c(NA, 3, 1, 4, NA, NA, 3, 4, 1, 2),
Q3 = c(3, 4, 1, 2, 4, NA, NA, 1, 1, 2),
Q4 = c(NA, 4, 1, 1, 1, 3, NA, 2, 2, NA))
我想使用 rowSums
函数对每行中不是“4”的值求和并排除 NA 并将结果除以非 4 和非 NA 的数量列(使用 dplyr 管道)。我不想替换底层数据框中的 4s;我想保持原样。
因为我不知道如何将结果除以非 4 列和非 NA 列的数量,所以我只尝试尝试问题的第一部分。我已经使用以下代码尝试了第一部分,但没有成功:
library(dplyr)
df <- df %>%
as.data.frame() %>%
mutate(sum = rowSums(.[. != 4, ], na.rm = TRUE))
所需的输出如下所示:
在上面的屏幕截图中,"mean" 列是非 4 和非 NA 值的总和除以非 4 和非 NA 列的数量。
谢谢!
如果我们想在 dplyr
中严格执行此操作,我们可以将 rowwise
与 do
一起使用,并计算每行不为 4 的值的总和,然后将它们除以 length
的值。
library(dplyr)
df %>%
rowwise() %>%
do( (.) %>% as.data.frame %>%
mutate(mean = sum(.[. != 4], na.rm = TRUE)/length(.[.!=4 & !is.na(.)])))
# Q1 Q2 Q3 Q4 mean
# * <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 1.00 NA 3.00 NA 2.00
# 2 4.00 3.00 4.00 4.00 3.00
# 3 2.00 1.00 1.00 1.00 1.25
# 4 3.00 4.00 2.00 1.00 2.00
# 5 1.00 NA 4.00 1.00 1.00
# 6 1.00 NA NA 3.00 2.00
# 7 4.00 3.00 NA NA 3.00
# 8 4.00 4.00 1.00 2.00 1.50
# 9 1.00 1.00 1.00 2.00 1.25
#10 2.00 2.00 2.00 NA 2.00
EDIT - 在发布答案后,现在我意识到我们实际上可以使用 mean
df %>%
rowwise() %>%
do( (.) %>% as.data.frame %>%
mutate(mean = mean(.[. != 4], na.rm = TRUE)))
sp_mean <- function(x) mean(x[!is.na(x) & x != 4])
df$mean <-
df %>%
apply(1, sp_mean)
df
Q1 Q2 Q3 Q4 mean
1 1 NA 3 NA 2.00
2 4 3 4 4 3.00
3 2 1 1 1 1.25
4 3 4 2 1 2.00
5 1 NA 4 1 1.00
6 1 NA NA 3 2.00
7 4 3 NA NA 3.00
8 4 4 1 2 1.50
9 1 1 1 2 1.25
10 2 2 2 NA 2.00
编辑 1 - 稍微更健壮:
df$mean <-
df %>%
select(matches("^Q\d+")) %>%
apply(1, sp_mean)
matches("^Q\d+")
匹配以 Q1, Q2,..., Q199, Q200, ...
编辑 2 - 将我的 sp_mean() 与 Ronak 的解决方案相结合(不需要 do() 吗?):
df %>%
rowwise() %>%
mutate(mean = sp_mean(c(Q1, Q2, Q3, Q4)))
使用 base R 你可以做:
df$mean = rowMeans(`is.na<-`(df,df==4),T)#or rowMeans(replace(df,df==4,NA),T)
> df
Q1 Q2 Q3 Q4 mean
1 1 NA 3 NA 2.00
2 4 3 4 4 3.00
3 2 1 1 1 1.25
4 3 4 2 1 2.00
5 1 NA 4 1 1.00
6 1 NA NA 3 2.00
7 4 3 NA NA 3.00
8 4 4 1 2 1.50
9 1 1 1 2 1.25
10 2 2 2 NA 2.00