如何在R中按条件统计有效响应数并生成新列?
高效统计tibble每行有效响应数(排除4和NA)
需求明确:给tibble数据框新增一列sum,统计每行中既不是NA也不等于4的数值个数,其余情况(值为4或NA)不计入统计。
测试数据
library(tibble) id <- c("agb", "efr", "h3z", "h8r", "p9o", "tr5", "g1f", "l95" ) c1 <- c(1:3, NA, 4, 9, 4, 4) c2 <- c(9, 4, 2, 2, 2, 7, 6, 5) c3 <- c(1, 1, 1, NA, NA, 3, 3, 4) c4 <- c(1, 1, 1, NA, NA, 3, 3, 4) DF <- tibble(id, c1, c2, c3, c4)
方法一:向量化rowSums(最高效,适合大数据集)
利用R的向量化运算直接批量处理整列,避免循环或逐行判断,效率远超ifelse:
library(dplyr) DF2 <- DF %>% mutate(sum = rowSums(!is.na(.[, -1]) & .[, -1] != 4))
解释:
.[, -1]:排除第一列id,只处理数值列!is.na(...):筛选非NA的值... != 4:筛选不等于4的值rowSums:对每行的符合条件的标记(TRUE=1,FALSE=0)求和
如果需要指定具体列(而非排除第一列),可以写成:
DF2 <- DF %>% mutate(sum = rowSums(!is.na(select(., c1:c4)) & select(., c1:c4) != 4))
方法二:dplyr + across(可读性优先)
如果更习惯dplyr的列遍历语法,用across指定目标列,再求和:
library(dplyr) DF2 <- DF %>% mutate(sum = rowSums(across(c1:c4, ~ !is.na(.x) & .x != 4)))
验证结果
运行上述代码后,DF2的sum列完全符合期望:
# 输出DF2 DF2 #> # A tibble: 8 × 6 #> id c1 c2 c3 c4 sum #> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> #> 1 agb 1 9 1 1 4 #> 2 efr 2 4 1 1 3 #> 3 h3z 3 2 1 1 4 #> 4 h8r NA 2 NA NA 1 #> 5 p9o 4 2 NA NA 1 #> 6 tr5 9 7 3 3 4 #> 7 g1f 4 6 3 3 3 #> 8 l95 4 5 4 4 1
为什么nrow、length没用?
nrow是统计数据框的总行数,length是统计单个向量的元素个数,都不是针对每行元素的条件统计,所以无法满足需求;而ifelse需要逐个列判断,当列数多的时候会非常繁琐,以上两种方法都是批量处理,代码简洁且效率高。
内容的提问来源于stack exchange,提问作者Laura31
相关产品推荐
相关产品推荐

