在dplyr中测试列子集非NA值是否全部相等的实现方法
我来帮你解决这个问题!你需要判断每行中所有非NA的列值是否都相同,用dplyr实现的话,其实有几种简洁的方式,比直接用all函数更灵活,尤其是列数多的时候。
首先先确认你的数据框:
mydf <- data.frame( col1 = c("Red", "Red", "Blue", "Orange"), col2 = c("Red", "Blue", NA, "Red"), col3 = c("Red", "Red", "Blue", "Red"), col4 = c("Red", "Red", "Blue", "Blue") )
方法一:用dplyr的rowwise + n_distinct(推荐,tidyverse风格)
这个方法最简洁,而且容易扩展到更多列:
library(dplyr) mydf <- mydf %>% rowwise() %>% # 对每行的col1到col4计算去重后的非NA值数量 mutate(all_equal = n_distinct(c_across(col1:col4), na.rm = TRUE) == 1) %>% ungroup()
运行后得到的结果和你期望的完全一致:
# A tibble: 4 × 5 col1 col2 col3 col4 all_equal <chr> <chr> <chr> <chr> <lgl> 1 Red Red Red Red TRUE 2 Red Blue Red Red FALSE 3 Blue NA Blue Blue TRUE 4 Orange Red Red Blue FALSE
原理很简单:c_across(col1:col4)会提取每行的目标列值,n_distinct(..., na.rm=TRUE)会忽略NA,计算剩下的值有多少种不同的类别。如果结果是1,说明所有非NA值都相同,就标记为TRUE,否则为FALSE。
方法二:不用rowwise,用apply(适合大数据,效率更高)
如果你处理的是大数据集,rowwise的效率可能稍低,这时候可以用基础R的apply逐行处理:
mydf$all_equal <- apply(mydf[, 1:4], 1, function(x) { # 去掉NA后,判断去重后的值数量是否为1 length(unique(na.omit(x))) == 1 })
为什么直接用all函数效果不好?
你提到用all函数在dplyr链式里效果不佳,大概率是因为all默认是对整个向量做全局判断,而不是逐行返回结果。比如直接写all(col1 == col2, na.rm=TRUE),会得到一个单一的逻辑值,而不是每行的判断结果。
如果非要用all,也可以在rowwise里实现,但需要手动写所有列的两两相等判断,列数多的时候会非常繁琐:
mydf %>% rowwise() %>% mutate(all_equal = all(col1 == col2, col2 == col3, col3 == col4, na.rm = TRUE)) %>% ungroup()
这个也能得到正确结果,但如果有10列,你就要写9个相等判断,显然不如n_distinct的方法简洁通用。
内容的提问来源于stack exchange,提问作者Parseltongue
相关产品推荐
相关产品推荐

