在R中统计所有规格列对的共同非NA行数
问题描述
我有一个数据框df,结构如下:
ID 001-alpha 001-sigma 001-delta 001-gamma 002-alpha 002-beta 002-charlie 002-delta 12 1 2 3 3 2 NA 2 0 21 NA 1 3 NA 3 2 2 NA 24 1 2 NA 3 3 1 3 2 36 NA 2 3 4 2 2 NA 1 44 NA 1 2 3 1 2 1 2 57 0 NA 2 3 1 1 3 1
数据框说明:
ID字段为唯一的产品ID;- 以
001-或002-开头的列代表产品的各项规格(注:实际dput输出中列名用.替代了-,处理时需注意)。
需求:统计每一对同前缀(001-或002-)的产品规格列中,同时包含非空(非NA)值的ID数量。
例如:
001-alpha和001-sigma两列,ID=12和ID=24均为非NA值,对应统计值为2;001-alpha和001-delta两列,符合条件的ID为12和57,统计值为2。
期望输出格式:
001-alpha-sigma 001-alpha-delta 001-alpha-gamma 001-sigma-delta 001-sigma-gamma 001-delta-gamma 002-alpha-beta 002-alpha-charlie 002-alpha-delta 002-beta-charlie 002-beta-delta 002-charlie-delta 2 2 3 4 4 4 5 5 5 4 4 4
附dput(df):
structure(list (ID = structure(1:6, .Label = c("12", "21", "24", "36", "44", "57"), class = "factor"), `001.alpha` = c(1L, NA, 1L, NA, NA, 0L), `001.sigma` = c(2L, 1L, 2L, 2L, 1L, NA), `001.delta` = c(3L, 3L, NA, 3L, 2L, 2L), `001.gamma` = c(3L, NA, 3L, 4L, 3L, 3L), `002.alpha` = c(2L, 3L, 3L, 2L, 1L, 1L), `002.beta` = c(NA,2L, 1L, 2L, 2L, 1L), `002.charlie` = c(2L, 2L, 3L, NA, 1L,3L), `002.delta` = c(0L, NA, 2L, 1L, 2L, 1L)), row.names = c(NA, -6L), class = "data.frame")
解决方案(基于dplyr生态)
可以通过分组列前缀、生成列对、逐对统计非NA交集数量的思路实现,具体步骤如下:
1. 加载所需包
library(dplyr) library(tidyr) library(purrr) library(stringr)
2. 预处理数据:统一列名格式并拆分前缀
先把列名中的.替换回-,再拆分出前缀和规格名:
# 替换列名中的.为-,统一格式 colnames(df) <- str_replace(colnames(df), "\\.", "-") # 提取所有规格列(排除ID列) spec_cols <- colnames(df)[colnames(df) != "ID"] # 拆分每个规格列的前缀(001/002)和具体规格名 spec_info <- str_split_fixed(spec_cols, "-", 2) %>% as.data.frame() %>% set_names(c("prefix", "spec")) %>% mutate(col = spec_cols)
3. 按前缀分组,生成列对并统计
对每个前缀组生成所有不重复的列对,计算每对列中同时非NA的行数:
# 按前缀分组处理 result_list <- spec_info %>% group_split(prefix) %>% map(function(group) { # 生成当前组内所有列的两两组合 col_pairs <- combn(group$col, 2, simplify = FALSE) # 统计每对列的非NA交集行数 map_dbl(col_pairs, function(pair) { df %>% filter(!is.na(!!sym(pair[1])) & !is.na(!!sym(pair[2]))) %>% nrow() }) %>% # 设置结果名称为"前缀-规格1-规格2"格式 set_names(map_chr(col_pairs, ~str_c(.x, collapse = "-"))) }) # 合并所有组的结果为单行数据框 final_result <- bind_cols(result_list)
4. 查看输出
运行后final_result的格式与期望一致:
print(final_result) # 输出: # 001-alpha-sigma 001-alpha-delta 001-alpha-gamma 001-sigma-delta 001-sigma-gamma 001-delta-gamma 002-alpha-beta 002-alpha-charlie 002-alpha-delta 002-beta-charlie 002-beta-delta 002-charlie-delta # 1 2 2 3 4 4 4 5 5 5 4 4 4
补充说明
- 用
group_split按前缀拆分列,确保只统计同前缀下的列对,避免跨组无效统计; combn生成不重复的两两组合,避免重复计算(如alpha-sigma和sigma-alpha只统计一次);!!sym(pair[1])用于将字符串格式的列名转换为dplyr可识别的变量,实现动态列引用。
内容的提问来源于stack exchange,提问作者Sandy
相关产品推荐
相关产品推荐

