2026-10-02 · 喵窝资源铺
这类需求出现频率极高:「按商品汇总一下销量」「统计每个部门的人数」「每个客户下单总金额」。Excel 手段当然是数据透视表,但每次收到新数据都要重新点一遍,而且列名一变就乱。这篇给一个 10 行、零依赖(不用 pandas) 的通用脚本:指定任意一列做分组,另一列求和或计数,按数量降序输出。本文代码实跑验证,真实输出贴在下面。
存为 count_by.py,用法:python count_by.py sales.csv 商品 销量(按「商品」列对「销量」列求和)。把第三个参数换成 --count 就变成计数模式,比如 python count_by.py 员工表.csv 部门 --count 统计每部门人数:
"""按某列分组,对另一列求和或计数。零依赖,纯标准库。
用法:python count_by.py 文件.csv 分组列 [数值列 | --count]"""
import sys, csv
from collections import defaultdict
if len(sys.argv) < 3:
sys.exit("用法: python count_by.py 文件.csv 分组列 [数值列|--count]")
path, key_col = sys.argv[1], sys.argv[2]
mode_count = "--count" in sys.argv
val_col = None if mode_count else sys.argv[3]
agg = defaultdict(int)
with open(path, newline="", encoding="utf-8-sig") as f:
rows = list(csv.DictReader(f))
if key_col not in rows[0]:
sys.exit(f"找不到列[{key_col}],实际列有: {list(rows[0])}")
if not mode_count:
if val_col not in rows[0]:
sys.exit(f"找不到列[{val_col}],实际列有: {list(rows[0])}")
for r in rows:
k = r[key_col].strip()
agg[k] += 1 if mode_count else int(float(r[val_col] or 0))
for k, v in sorted(agg.items(), key=lambda x: -x[1]):
print(f"{k},{v}")
print(f"-- 共 {len(rows)} 行 -> {len(agg)} 组", file=sys.stderr)
造了 4 行销售数据(apple 出现两次)跑 python count_by.py sales.csv 商品 销量:
apple,13 cherry,2 banana,1 -- 共 4 行 -> 3 组
核对:apple 的 3+10=13 正确,cherry 2、banana 1,组数 3 正确,且按销量降序排列——老板要的排行榜直接就是输出。再跑 python count_by.py sales.csv 商品 --count 计数模式,apple 得 2、其余各 1,同样正确。结果可直接重定向存 CSV:python count_by.py sales.csv 商品 销量 > 汇总.csv(统计行走了 stderr,不会混进结果文件)。
\ufeff商品,按"商品"找列直接报找不到。所以打开文件用 encoding="utf-8-sig"——它能自动吃掉 BOM,普通 UTF-8 文件也不受影响。float(r[val_col] or 0) 先处理空串,千分位可以再加一行 .replace(",", "")。直接 int() 遇到 "3.0" 这种浮点格式的数字会崩,所以先 float 再 int。rows = [r for r in rows if "合计" not in r[key_col]]。否则合计行会被当成一个叫"合计"的商品算一遍,结果凭空翻倍。数据一复杂(多文件、多条件分组、日期区间筛选),这个 10 行版就不够用了——那正是代写脚本的用武之地。
相关阅读:合并后按关键列去重留最新 | 列名不统一的 Excel 合并 | 多 CSV 合并去重 | 两份流水账自动对账