如何用tidyverse高效筛选分组内无重复值的列并精简数据集
高效精简混合格式数据集的tidyverse单管道方案
问题背景
我有一个混合长/短格式的大型数据集:部分列按id和visit分组后值唯一,另一部分列每组内有多个值。短格式数据为匹配长格式被重复填充,导致出现大量重复行。已有的筛选精简方案运行速度较慢,需要一个基于tidyverse的高效单管道解决方案。
示例数据生成
library(tidyverse) n_id = 200 n_visit = 15 r = 20 N = n_id*n_visit*r df = tibble( id=rep(1:n_id, each=n_visit*r), visit=rep(paste0("v", 1:n_visit), times=n_id*r), ) %>% mutate( !!!set_names(rep(NA, 50), paste0("short",1:50)), !!!set_names(rep(NA, 50), paste0("long",1:50)), across(starts_with("short"), ~visit), across(starts_with("long"), ~rnorm(n())), ) %>% arrange(id, visit) # 验证列特性:short列每组唯一,long列每组多值 df %>% summarise(a=n_distinct(short1), .by=c(id, visit)) %>% pull() %>% unique() #> [1] 1 df %>% summarise(a=n_distinct(long1), .by=c(id, visit)) %>% pull() %>% unique() #> [1] 20
高效单管道解决方案
df %>% group_by(id, visit) %>% summarise( # 对每列:如果组内唯一则保留该值,否则标记为NA across(everything(), ~if(n_distinct(.x) == 1) first(.x) else NA), .groups = "drop" # 分组后自动取消分组 ) %>% # 筛选掉全为NA的列(即原数据中每组多值的列) select(where(~!all(is.na(.x)))) %>% # 确保无重复行(分组汇总后已基本无重复,此步为冗余保障) distinct()
方案优势
- 速度优化:使用
n_distinct()替代length(unique(.x)),n_distinct针对tidyverse分组场景做了性能优化,计算更快 - 单管道完成:无需创建中间变量,减少内存占用与数据拷贝开销
- 一步到位:在分组汇总阶段直接完成值提取与无效列标记,后续仅需筛选有效列即可得到目标数据集
内容的提问来源于stack exchange,提问作者Dan Chaltiel
相关产品推荐
相关产品推荐

