如何高效实现文件中基于前两列唯一组合的列均值计算?
高效解决文本数据分组求均值的方案
嘿,这个需求完全不用写复杂的循环,Python里有两个超高效的方案,比手动遍历判断分组简洁太多了,而且性能还好!
方案一:用标准库collections.defaultdict(无需额外安装)
这个方案用Python自带的工具就能搞定,时间复杂度是O(n)(n是数据组数),比手动循环判断分组高效很多:
from collections import defaultdict # 用字典存储每个组合的统计数据:键是(col1, col2)元组,值是[col3总和, col4总和, 数据条数] group_stats = defaultdict(lambda: [0.0, 0.0, 0]) with open(r"C:\Users\priya\Desktop\test.txt") as f: # 读取所有内容,按空格分割成列表 all_data = f.read().split() # 每4个元素为一组,遍历所有数据 for idx in range(0, len(all_data), 4): # 跳过不完整的分组(如果文件末尾有残缺数据) if idx + 3 >= len(all_data): continue # 提取当前组的四个元素 key = (all_data[idx], all_data[idx+1]) num3 = float(all_data[idx+2]) num4 = float(all_data[idx+3]) # 更新统计值 group_stats[key][0] += num3 group_stats[key][1] += num4 group_stats[key][2] += 1 # 生成最终结果并输出 for combo, (sum3, sum4, count) in group_stats.items(): avg3 = sum3 / count avg4 = sum4 / count # 格式化输出:整数显示为整数,小数保留一位(和你的示例格式一致) formatted_avg3 = int(avg3) if avg3.is_integer() else round(avg3, 1) formatted_avg4 = int(avg4) if avg4.is_integer() else round(avg4, 1) print(f"{combo[0]} {combo[1]} {formatted_avg3} {formatted_avg4}")
为什么这个方案更好?
- 用
defaultdict自动帮你管理分组,不用手动判断“这个组合有没有出现过”,代码更简洁 - 一次遍历就能完成统计,性能比嵌套循环高很多
- 完全依赖Python标准库,不需要安装额外包
方案二:用pandas(适合大数据或复杂数据处理)
如果你的数据量很大,或者之后还要做更多数据操作(比如排序、过滤),用pandas会更省心,它内部做了大量性能优化:
import pandas as pd # 读取文本文件:按空格分隔,指定列名 df = pd.read_csv( r"C:\Users\priya\Desktop\test.txt", sep="\s+", # 匹配任意数量的空格作为分隔符 header=None, names=["col1", "col2", "col3", "col4"] ) # 按前两列分组,计算后两列的平均值 result_df = df.groupby(["col1", "col2"]).mean().reset_index() # 格式化数值,和示例输出格式一致(整数显示整数,小数保留一位) result_df["col3"] = result_df["col3"].apply(lambda x: int(x) if x.is_integer() else round(x, 1)) result_df["col4"] = result_df["col4"].apply(lambda x: int(x) if x.is_integer() else round(x, 1)) # 输出结果 for _, row in result_df.iterrows(): print(f"{row['col1']} {row['col2']} {row['col3']} {row['col4']}")
这个方案的优势:
- 代码更简洁,分组求均值只用一行
groupby().mean()就搞定 - 处理十万级甚至百万级数据时,性能比手动写的循环快很多
- 后续可以轻松扩展:比如给结果排序、过滤特定组合、把结果写入新文件等
小提示
如果你的文件里有多余的空行或者连续空格,上面的代码都能自动处理,因为split()和sep="\s+"会忽略这些无效内容。
内容的提问来源于stack exchange,提问作者sahil10
相关产品推荐
相关产品推荐

