Pandas 移除非高频标签行:实现Top200高频标签对应行筛选
适配低内存场景的Pandas高效实现方案
针对100万行规模、全量加载占用过高内存的筛选需求,全程采用分块流式处理逻辑,不需要一次性加载全量数据集,完全绕开CountVectorizer构建大尺寸稀疏矩阵占满内存的问题。
核心实现逻辑
整个流程分两步走,仅需两次遍历数据集即可完成全流程,全程内存占用可控:
- 第一遍流式遍历全量数据,逐块统计所有标签的出现频次,汇总后拿到频次Top200的目标标签集合
- 第二遍再次流式遍历全量数据,逐块筛选出tags列和目标标签集合有交集的行,拼接成最终筛选后的数据集
具体实现代码
第一步:分块统计标签频次,获取Top200目标标签
不需要全量加载数据,每次只读取固定大小的块进内存处理,累计统计所有标签的出现次数:
import pandas as pd from collections import Counter import ast # 全局计数器,累计所有标签的出现次数 global_tag_counter = Counter() # 分块大小根据自身内存调整,内存较小的话可以设为5000-10000行/块 chunksize = 10000 # 分块读取全量数据集 for chunk in pd.read_csv("你的原始数据集路径.csv", chunksize=chunksize): # 把字符串格式的tags列转换为真实的Python列表,避免解析错误 chunk["tags"] = chunk["tags"].apply(ast.literal_eval) # 拉平当前块内所有标签,累计到全局计数器 current_block_tags = [tag for tag_list in chunk["tags"] for tag in tag_list] global_tag_counter.update(current_block_tags) # 提取出现频次最高的200个标签,用set存储方便后续快速做交集判断 top200_tags = set(tag for tag, count in global_tag_counter.most_common(200))
第二步:分块筛选符合条件的记录
同样采用分块读取的方式,逐块判断当前块内的行是否包含目标标签,把符合条件的块依次追加写入结果文件,避免内存堆积:
# 控制写入时是否带表头,第一次写文件时带表头,后续追加不需要 write_table_header = True for chunk in pd.read_csv("你的原始数据集路径.csv", chunksize=chunksize): chunk["tags"] = chunk["tags"].apply(ast.literal_eval) # 用集合交集快速判断该行是否包含至少一个目标标签 is_qualify = chunk["tags"].apply(lambda tag_list: len(set(tag_list) & top200_tags) > 0) # 筛选出符合条件的行 filtered_chunk = chunk[is_qualify] # 追加写入结果文件,不保留行索引 filtered_chunk.to_csv("筛选完成的数据集.csv", mode="a", header=write_table_header, index=False) # 第一次写完表头后,后续都改为False write_table_header = False
优化说明
- 该方案解决了之前使用CountVectorizer效果不佳的两个核心问题:一是CountVectorizer默认按空格拆分字符串,无法准确识别列表格式存储的标签内容,容易出现统计偏差;二是构建和6万多标签维度对齐的稀疏矩阵会一次性占用大量内存,容易触发资源不足的报错
- 相比CountVectorizer方案,该方案不会生成全量稀疏矩阵,内存占用仅和单次读取的块大小相关,哪怕数据集规模到千万行也能正常运行
- 标签匹配采用集合交集的判断方式,计算效率远高于逐行字符串匹配,不会因为标签总数多拖慢处理速度
- 如果处理时
ast.literal_eval的解析速度偏慢,可针对标签格式做适配:因为tags列是固定格式的字符串,可以直接用字符串包含判断快速校验,只要注意短标签的边界匹配(比如避免"java"误匹配到"javascript"的字符串内容),处理速度还能进一步提升 - 统计得到的Top200标签集合可以单独存在本地文件中,后续重复筛选时不需要重新跑第一遍的统计流程,节省处理时间
内容的提问来源于stack exchange,提问作者najuspy
相关产品推荐
相关产品推荐

