如何计算相邻行的平均值(按前缀分组)

本文介绍如何使用纯 python 读取文本文件,按首列键名前缀(如 apple_1、apple_2)自动识别逻辑组,并对每组内所有相邻行(以 `_1` 为组起始标志)的数值列求平均值,最终输出简洁汇总结果。

在处理结构化但非标准的文本数据时(例如实验记录、日志摘要或批量采集结果),常需对“逻辑连续行”进行聚合——而非简单按固定行数分组。本例中,数据以 xxx_1、xxx_2、xxx_3 等形式隐式定义组边界:每个 _1 表示新组开始,其后连续的同前缀行(如 apple_2、apple_3)属于同一组;组内所有数值列(第2–4列)需逐列求平均,前缀(如 apple)作为输出标识。

以下为完整可运行解决方案(无需 Pandas 或 NumPy,仅依赖内置模块):

def averages(lst, n):
    """生成器:对列表中每个元素除以 n,返回浮点平均值"""
    for v in lst:
        yield v / n

def dump(prev, cols, count):
    """输出当前组结果:前缀 + 各列平均值(保留小数)"""
    if prev:
        print(prev, *averages(cols, count))

# 主逻辑:逐行解析,动态累积并触发输出
with open("example.txt") as data:
    cols = []      # 存储当前组所有数值列的累加和(长度=列数)
    count = 0      # 当前组已处理行数
    prev = None    # 当前组前缀(如 'apple')

    for line in data:
        line = line.strip()
        if not line:  # 跳过空行
            continue
        parts = line.split()
        key, *values = parts
        nums = list(map(float, values))  # 强制转 float,支持小数输入

        # 拆分键:apple_2 → ('apple', '2')
        fruit, suffix = key.rsplit("_", 1)

        if suffix == "1":
            # 遇到新组起点:先输出上一组结果(如有),再重置状态
            dump(prev, cols, count)
            prev = fruit
            cols = nums.copy()  # 初始化新组累加数组
            count = 1
        else:
            # 同组后续行:逐列累加
            for i in range(len(nums)):
                cols[i] += nums[i]
            count += 1

    # 文件结束,输出最后一组
    dump(prev, cols, count)

关键设计说明:

  • 组识别机制:严格以 _1 作为组起始信号(如 book

    _1、cook_1),确保逻辑清晰、无歧义;
  • 内存友好:不加载全部数据到内存,适合大文件流式处理;
  • 类型安全:使用 float() 转换,兼容整数与小数输入;
  • ⚠️ 注意事项
    • 输入文件需保证每行至少含 2 列(键 + 一个数值),否则 rsplit("_", 1) 或 map(float, values) 可能报错,建议增加异常处理(如 try/except ValueError);
    • 若存在 xxx_0 或非数字后缀(如 xxx_a),需扩展 suffix == "1" 的判断逻辑;
    • 输出为标准浮点格式(如 2.0),如需控制小数位数,可在 print 中使用格式化:f"{v:.1f}"。

运行后,输入示例将精准输出:

apple 2.0 3.0 4.0
book 1.0 4.0 5.0
cook 3.0 5.0 6.0
book 2.0 3.0 4.0

该方案兼顾可读性、健壮性与低依赖性,是处理此类“隐式分组+行间聚合”任务的典型 Python 实践。