如何高效统计Pandas列中逗号分隔重复值的出现次数?
嘿,我太懂你这种大数据集下卡壳的感受了——原来的循环+extend方式在数据量上去之后,因为Python循环的开销实在太高,肯定会慢到让人抓狂。这里有几个高效的向量化解决方案,能帮你把速度提上去好几个档次:
方案1:用pandas的explode(推荐,简洁又高效)
如果你的pandas版本在0.25及以上,explode绝对是最优选择,它能直接把列表格式的列拆成单行,全程都是pandas内部的向量化操作,比Python循环快N倍:
# 拆分时顺便处理逗号后的空格,避免出现带空格的类别值 split_cats = response['Category'].str.split(',\s*', expand=False) # 展开列表为单行,再统计计数 cato_counts = split_cats.explode().value_counts().sort_values(ascending=False).to_frame()
小提示:用,\s*而不是单纯的,,是为了处理原数据里逗号后可能带的空格(比如Literacy & Language, Special Needs),避免统计出' Literacy & Language'(带前置空格)和'Literacy & Language'两个不同的类别。
方案2:用str.get_dummies+sum(兼容旧版pandas)
如果你的pandas版本比较旧没法用explode,可以用哑变量的方式来统计,同样是纯向量化操作,性能拉满:
# 按逗号+空格拆分,生成哑变量矩阵 dummy_matrix = response['Category'].str.get_dummies(sep=',\s*') # 对每列求和,就是对应类别的总出现次数 cato_counts = dummy_matrix.sum().sort_values(ascending=False).to_frame()
这个方法的原理是把每个类别变成一列,每行中对应类别的位置标记为1,其余为0,求和后直接得到每个类别的总计数,完全没有Python层面的循环,大数据集下速度极快。
方案3:用itertools.chain+Counter(纯Python优化)
如果需要纯Python的实现方式,也可以用itertools.chain来避免创建大列表(节省内存),配合Counter统计:
from collections import Counter from itertools import chain # 生成一个迭代器,逐个读取拆分后的类别,避免一次性加载所有数据到内存 cat_iterator = chain.from_iterable(response['Category'].str.split(',\s*').dropna()) # 统计计数并转成DataFrame cato_counts = pd.Series(Counter(cat_iterator)).sort_values(ascending=False).to_frame()
这个方法比你原来的extend循环要高效,因为chain.from_iterable是惰性迭代,不会把所有类别都塞进一个大列表里,内存占用更低,统计速度也更快。
总的来说,优先推荐前两个pandas原生的向量化方案,因为它们的底层都是C实现的,在大数据集下的性能会比纯Python循环好几个数量级。
内容的提问来源于stack exchange,提问作者user517696

