R中length(unique())替代n_distinct()的多列计数问题与传参咨询
问题原因与解决方案
问题1:length(unique(across(all_of(vars))))返回2的原因
across(all_of(vars))会返回一个包含指定列的tibble(子数据框),unique()处理这个tibble后得到的仍是一个tibble(包含该组内多列组合的唯一行)。而length()作用于tibble时,返回的是列的数量,不是唯一行的数量,所以你得到了vars的长度2,而非预期的唯一组合数。
问题2:length(unique(Sepal.Length, Petal.Width))返回15的原因
unique()函数仅接受第一个参数作为待去重的向量,后续参数会被当作函数的可选参数(比如fromLast)使用。当你传入两个变量时,Petal.Width会被强制转换为逻辑值,实际执行的是对Sepal.Length单列的去重计数——setosa组的Sepal.Length恰好有15个唯一值,所以得到15,这和多列组合的唯一计数完全无关。
解决方案:用字符向量列名实现高效多列去重计数
方式1:在dplyr管道内实现
利用cur_data()获取当前分组的数据集,通过字符向量筛选列后,用unique()获取唯一行再计数:
foo <- iris |> group_by(Species) |> mutate( raw_count = n(), adjusted_count = nrow(unique(cur_data()[vars])) )
对setosa组,该代码会返回预期的28。
方式2:用data.table实现更高性能(适合超大型数据集)
data.table的uniqueN()函数原生支持按指定列计数唯一组合,性能远高于n_distinct(),尤其适合大型数据集:
library(data.table) dt <- as.data.table(iris) foo <- dt[, .( raw_count = .N, adjusted_count = uniqueN(.SD, by = vars) ), by = Species] # 可选:转回tibble格式 foo <- as_tibble(foo)
内容的提问来源于stack exchange,提问作者Tom Stanton
相关产品推荐
相关产品推荐

