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

如何为R数据框按列子集生成非NA计数列与均值列?

在R数据框中按前缀分组添加非NA计数与行均值列

问题背景

现有如下示例数据框,需要按列名前缀(如var1、var2)生成两类新列:

  • 对应前缀列子集的非NA值计数(如var1_count、var2_count)
  • 对应前缀列子集的行均值(如avg_var1、avg_var2)

示例数据生成代码:

set.seed(123)
df <- data.frame( id = 1:5,
                  var1_a = runif(1:5),
                  var1_b = runif(1:5),
                  var2_a = runif(1:5),
                  var2_b = runif(1:5))
df[, "var1_a"][ df[, "var1_a"] < 0.5 ] <- NA
df[, "var2_b"][ df[, "var2_b"] > 0.5 ] <- NA

处理后的数据框:

id    var1_a    var1_b    var2_a     var2_b
1  1        NA 0.0455565 0.9568333         NA
2  2 0.7883051 0.5281055 0.4533342 0.24608773
3  3        NA 0.8924190 0.6775706 0.04205953
4  4 0.8830174 0.5514350 0.5726334 0.32792072
5  5 0.9404673 0.4566147 0.1029247         NA

之前尝试的代码因不理解正则\\..*导致匹配错误,同时实际列名存在大小写差异(如brand_m1_A和Brand_m1_B),需要解决这些问题。

关键概念解释:\\..*正则表达式

\\..*是正则表达式的写法:

  • \\.:匹配点号(正则中点号是通配符,需用反斜杠转义,R里要写两个反斜杠)
  • .*:匹配点号之后的任意长度字符
  • 所以gsub("\\..*", "", names(df))的作用是:把列名中第一个点及后面的所有内容删除,提取前缀(比如var1_a变成var1,brand_m1_A变成brand)

解决大小写差异问题

如果列名前缀存在大小写不同(如brand和Brand),默认分组会把它们当成不同组,需要先统一前缀的大小写:

  • 转成小写:tolower(gsub("\\..*", "", names(df)))
  • 转成大写:toupper(gsub("\\..*", "", names(df)))

具体解决方案

方法1:Base R实现

直接基于分组计算计数和均值,再合并到原数据框:

# 提取分组前缀(统一转小写处理大小写差异)
groups <- tolower(gsub("\\..*", "", names(df)))
# 排除id列,只处理数值列
num_cols <- df[, !names(df) %in% "id"]
grouped_cols <- split.default(num_cols, groups)

# 计算非NA计数
count_cols <- lapply(grouped_cols, function(x) rowSums(!is.na(x)))
names(count_cols) <- paste0(names(count_cols), "_count")

# 计算行均值(忽略NA)
mean_cols <- lapply(grouped_cols, function(x) rowMeans(x, na.rm = TRUE))
names(mean_cols) <- paste0("avg_", names(mean_cols))

# 合并所有列
df_result <- cbind(df, count_cols, mean_cols)

运行后得到的结果:

id    var1_a    var1_b    var2_a     var2_b var1_count var2_count   avg_var1   avg_var2
1  1        NA 0.0455565 0.9568333         NA          1          1 0.04555650 0.95683330
2  2 0.7883051 0.5281055 0.4533342 0.24608773          2          2 0.65820530 0.34971097
3  3        NA 0.8924190 0.6775706 0.04205953          1          2 0.89241900 0.35981507
4  4 0.8830174 0.5514350 0.5726334 0.32792072          2          2 0.71722620 0.45027707
5  5 0.9404673 0.4566147 0.1029247         NA          2          1 0.69854100 0.10292470

方法2:tidyverse(dplyr + stringr)实现

更直观的管道式操作,适合复杂数据处理:

library(dplyr)
library(stringr)

df_result <- df %>%
  rowwise() %>%
  mutate(
    var1_count = sum(!is.na(c_across(starts_with("var1")))),
    var2_count = sum(!is.na(c_across(starts_with("var2")))),
    avg_var1 = mean(c_across(starts_with("var1")), na.rm = TRUE),
    avg_var2 = mean(c_across(starts_with("var2")), na.rm = TRUE)
  ) %>%
  ungroup()

如果实际列名是brand_m1_A这类,只需把starts_with("var1")改成starts_with(str_to_lower("Brand"))(统一大小写匹配)即可。


内容的提问来源于stack exchange,提问作者Victor Shin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:45:41