You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 21:06:28