dplyr中pick()与c_across()在行缺失值统计中的差异及相关问题
dplyr中pick()与c_across()在行缺失值统计中的差异及相关问题
嘿,我来帮你逐个拆解这几个关于dplyr工具的问题,保证说得明明白白!
1. pick() 和 c_across() 到底有啥不一样?
简单来说,这俩函数在rowwise()环境下的返回类型完全不同:
pick()返回的是迷你tibble(数据框):每行对应一个只包含当前行目标列的小数据框,完全保留原列的类型,哪怕各列类型不一样也能正常处理。c_across()返回的是原子向量:它会把当前行目标列的值合并成一个单一向量,这就要求这些列的类型能被兼容转换(比如数值和字符会被统一转成字符型),如果类型差异太大,很容易触发意外行为。
2. 怎么让第二个代码块正常工作?
你的第二个代码块出问题的核心原因是:c_across() 试图把字符型的a_letter和数值型的a_number合并成一个向量,虽然类型转换能完成,但有时候会因为类型兼容问题导致sum(is.na(...))无法正确计算(比如旧版dplyr里可能返回列表而非向量)。
给你两个实用的修复方案:
方案一:手动遍历判断缺失值
不管列类型如何,都能准确统计缺失值:
tibble( a_letter=sample(c(NA,"a","b"),size = 10,replace = T), a_number=sample(c(NA,1,2),size = 10,replace = T), hi="world" ) |> rowwise() |> mutate(empty_measurements = c_across(matches("a_")) %>% lapply(is.na) %>% unlist() %>% sum())
方案二:跳出rowwise,用更高效的写法
其实统计每行缺失值根本不需要rowwise(),直接用rowSums结合select更简洁高效:
tibble( a_letter=sample(c(NA,"a","b"),size = 10,replace = T), a_number=sample(c(NA,1,2),size = 10,replace = T), hi="world" ) |> mutate(empty_measurements = rowSums(is.na(select(matches("a_")))))
3. 为啥有人会觉得pick()是个坏选择?其实它在这里反而更靠谱!
你说反啦!在这个统计跨列缺失值的场景里,pick()才是更安全的选择,根本不是坏选择:
- 它保留了原数据的列结构,不需要做任何类型转换,
is.na(pick(...))会逐个判断每个列的缺失值,sum()在rowwise()环境下会自动把当前行的所有布尔值加总,完美统计缺失数量。 - 而
c_across()反而受限于向量的类型统一性,当列类型多样时,要么被迫做类型转换(可能隐藏风险),要么在旧版本里直接报错。
所以你的直觉其实没问题,但这里pick()的表现比c_across()更适配这个需求哦!
备注:内容来源于stack exchange,提问作者Aegis
相关产品推荐
相关产品推荐

