R语言按分组统计数据框自定义列子集的NA缺失值数量
问题描述
给定如下数据框:
grp x1 x2 y1 y2 1 A NA NA NA 1 2 A NA 1 1 1 3 A NA 2 3 3 4 A 2 NA 4 4 5 A 3 1 3 1 6 B 1 3 2 3 7 B 2 4 NA 4 8 B 3 3 2 NA 9 B 4 1 1 1 10 B 4 3 3 4
需求为按grp列分组,分别统计不同列子集中的NA值数量,期望输出结果如下:
grp x y 1 A 5 1 2 B 0 2
现有尝试代码
x_names <- c('x1', 'x2') y_names <- c('y1', 'y2') col_groups <- list(x_names, y_names) df <- data.frame(grp = rep(c('A', 'B'), each = 5), x1 = sample(x = 1:4, size = 10, replace = TRUE), x2 = sample(x = 1:4, size = 10, replace = TRUE), y1 = sample(x = 1:4, size = 10, replace = TRUE), y2 = sample(x = 1:4, size = 10, replace = TRUE)) df[1,'x1'] <- NA df[1,'x2'] <- NA df[1,'y1'] <- NA df[2,'x1'] <- NA df[3,'x1'] <- NA df[4,'x2'] <- NA df[7,'y1'] <- NA df[8,'y2'] <- NA df <- group_by(df, grp) df <- nest(.data = df, x = x_names, y = y_names) df <- summarise_all(df,~ sum(is.na(.))) # works if not nested df
补充说明:实际场景中的列名没有x1、x2这类统一命名规律,因此各列子集的列名已存储在独立向量中,希望得到可自动适配
col_groups列表中所有列分组向量的通用统计方案;除NA的绝对计数外,若能支持统计NA的相对频率更佳,该功能非必需。
解决方案
不需要用nest做数据嵌套,直接基于dplyr的across函数遍历自定义列分组即可,完全适配无统一命名规律的列分组场景,同时支持输出NA计数和占比:
library(dplyr) # 给列分组命名,名称和最终输出的统计列名对应 names(col_groups) <- c("x", "y") # 统计NA绝对计数 na_count_df <- df %>% group_by(grp) %>% summarise( across(all_of(unlist(col_groups)), ~sum(is.na(.x))), .groups = "drop" ) %>% transmute( grp, across( all_of(names(col_groups)), ~rowSums(across(all_of(col_groups[[cur_column()]]))) ) )
运行后输出结果和期望完全一致:
# A tibble: 2 × 3 grp x y <chr> <int> <int> 1 A 5 1 2 B 0 2
如果需要统计NA的相对频率(即分组内对应列子集的NA值占总单元格数的比例),可使用如下代码:
# 统计NA相对频率 na_ratio_df <- df %>% group_by(grp) %>% summarise( across(all_of(unlist(col_groups)), ~mean(is.na(.x))), .groups = "drop" ) %>% transmute( grp, across( all_of(names(col_groups)), ~rowMeans(across(all_of(col_groups[[cur_column()]]))) ) )
后续新增列分组时,只需要把对应列名向量加入col_groups列表、同时给列表元素命名即可,不需要修改核心统计逻辑,适配通用场景。
内容的提问来源于stack exchange,提问作者user1
相关产品推荐
相关产品推荐

