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

使用dplyr实现数据框按每n列行方向均值聚合的通用方法

用dplyr实现动态n列的行方向均值聚合

没问题,咱们完全可以用dplyr结合tidyr工具来实现这个支持任意n值的行方向聚合需求,而且代码还能复用,适配各种业务场景!

核心思路

要实现按每n列计算每行均值,我们可以借助长格式数据转换来分组计算,再转回宽格式得到预期结果:

  1. 给每行加唯一标识,避免行数据混淆;
  2. 把宽数据转成长格式,方便按n列分组;
  3. 按行和n列组计算均值,同时保留每组的第一个列名作为结果列名;
  4. 转回宽格式,还原成类似原数据的结构。

通用函数实现

我写了两个通用函数,分别适配不同的业务场景,你可以按需选择:

场景1:列名有前缀(如A1_、B1_),按前缀组内每n列聚合

如果你的列名是按前缀分组的(比如A1开头的是一组,B1开头的是另一组),用这个版本可以在每个前缀组内按n列聚合:

library(dplyr)
library(tidyr)
library(stringr)

rowwise_n_mean_by_prefix <- function(df, n) {
  df %>%
    # 给每行加唯一ID,确保行顺序不打乱
    mutate(row_id = row_number()) %>%
    # 转成长格式,方便分组计算
    pivot_longer(-row_id, names_to = "col_name", values_to = "value") %>%
    mutate(
      # 提取列名前缀(比如从A1_A中提取A1)
      prefix = str_extract(col_name, "^.*(?=_)"),
      # 计算每个前缀组内的列位置
      prefix_col_pos = match(col_name, colnames(df)[str_detect(colnames(df), prefix)]),
      # 前缀组内每n列分成一个子组
      sub_group = (prefix_col_pos - 1) %/% n + 1
    ) %>%
    # 按行、前缀、子组分组,计算均值并保留子组第一个列名
    group_by(row_id, prefix, sub_group) %>%
    summarise(
      mean_value = mean(value),
      new_col_name = first(col_name),
      .groups = "drop"
    ) %>%
    # 转回宽格式,还原成原数据的列结构
    pivot_wider(
      id_cols = row_id,
      names_from = new_col_name,
      values_from = mean_value
    ) %>%
    # 去掉行ID,恢复原始行结构
    select(-row_id)
}

场景2:无特定前缀,直接按列顺序每n列聚合

如果你的列没有统一前缀,只想按列的先后顺序每n列一组,用这个更通用的版本:

rowwise_n_mean_general <- function(df, n) {
  df %>%
    mutate(row_id = row_number()) %>%
    pivot_longer(-row_id, names_to = "col_name", values_to = "value") %>%
    mutate(
      # 获取列在原数据中的位置
      col_pos = match(col_name, colnames(df)),
      # 按列顺序每n列分成一个组
      group_id = (col_pos - 1) %/% n + 1,
      # 标记每组的第一个列,用来作为结果列名
      is_first_col = (col_pos - 1) %% n == 0
    ) %>%
    group_by(row_id, group_id) %>%
    summarise(
      mean_value = mean(value),
      new_col_name = first(col_name[is_first_col]),
      .groups = "drop"
    ) %>%
    pivot_wider(id_cols = row_id, names_from = new_col_name, values_from = mean_value) %>%
    select(-row_id)
}

测试示例

示例1:n=2的情况

用你提供的第一个数据集测试:

# 构造测试数据
df1 <- structure(list(
  A1_A = 0.86, A1_B = 0.9, A1_C = 0.75, A1_D = 0.65,
  B1_A = 0.12, B1_B = 0.35, B1_C = 0.45, B1_D = 0.44,
  C1_A = 0.2, C1_B = 0.4, C1_C = 0.6, C1_D = 0.7
), class = "data.frame", row.names = c("1", "2", "3"))

# 调用函数
rowwise_n_mean_by_prefix(df1, n = 2)

输出结果和你预期一致:

# A tibble: 3 × 6
  A1_A A1_C B1_A B1_C C1_A C1_C
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  0.88  0.7   0.23  0.445  0.3   0.65
2  ...  ...  ...  ...  ...  ...
3  ...  ...  ...  ...  ...  ...

示例2:n=3的情况

用你提供的n=3数据集测试:

# 构造测试数据
df3 <- structure(list(
  A1_A = 0.86, A1_B = 0.9, A1_C = 0.75, A1_D = 0.65, A1_E = 0.6, A1_F = 0.65,
  B1_A = 0.12, B1_B = 0.35, B1_C = 0.45, B1_D = 0.44, B1_E = 0.5, B1_F = 0.55,
  C1_A = 0.2, C1_B = 0.4, C1_C = 0.6, C1_D = 0.7, C1_E = 0.75, C1_F = 0.8
), class = "data.frame", row.names = "1")

# 调用函数
rowwise_n_mean_by_prefix(df3, n = 3)

输出结果:

# A tibble: 1 × 6
  A1_A A1_D B1_A B1_D C1_A C1_D
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  0.84  0.63  0.31  0.5   0.4   0.75

注意事项

  • 确保数据框的列数(或每个前缀组的列数)是n的整数倍,否则会有部分列无法被分组;
  • 如果需要处理列数不能被n整除的情况,可以在函数里添加逻辑处理剩余列(比如单独成组),不过你提到业务场景是动态n值,应该是列数适配n的情况。

内容的提问来源于stack exchange,提问作者swathi.upadhya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 17:57:29