Python中多条件匹配关键词词频高效统计方案咨询
现有代码问题梳理
- 逻辑错误:筛选出符合条件的
temp数据集后,调用count_words时传入的是全量data,导致统计结果完全不符合预期 - 时间复杂度极高:循环逻辑倒置,1500组条件每组都对全量5万条数据做过滤,累计产生7500万次无效计算
- 遍历效率极低:使用pandas的
iterrows遍历数据,性能比原生Python循环低1~2个数量级,且重复做类型判断和ast.literal_eval转换 - 存储结构不合理:将词频统计的
defaultdict存在DataFrame单元格中,读写开销远高于直接操作Python字典
优化实现方案
核心思路
把「按条件遍历过滤数据」改为「遍历单次数据匹配所有符合的条件」,将时间复杂度从O(N*M)(N为数据量,M为条件组数)降到O(N)
优化后代码
from collections import defaultdict import pandas as pd import ast import datetime from pathlib import PurePath # ========== 1. 预生成条件查询字典 ========== cat_ids = [subcats['id'] for subcats in cp.cat_config['cat'].values()] # 原有多索引生成逻辑保留 index = pd.MultiIndex.from_product([cat_ids, data.code.unique(), [start_date.strftime("%Y%m%d")], data.target.unique(), [datetime.datetime.strptime(str(data._dates.unique()[0]), "%Y%m%d").date().isocalendar()[1]]], names=["category_code", "region_code", "start_date", "target", "year_week"]) top_word_id = pd.DataFrame(index=index).reset_index() # 把条件转成字典,key为(分类id, target, 区域code),value为对应词频统计对象 cond_map = {} for idx, row in top_word_id.iterrows(): key = (row['category_code'], row['target'], row['region_code']) cond_map[key] = { 'rel': defaultdict(int), 'pos': defaultdict(int), 'neg': defaultdict(int) } # 定义列表类型转换函数,读数据时一次性转换 def parse_list(x): return ast.literal_eval(x) if isinstance(x, str) else x # ========== 2. 遍历日期处理数据 ========== while dates_queue: date = dates_queue.popleft() date_str = date.strftime("%Y%m%d.tsv") # 读数据时直接完成单词列的类型转换,避免后续重复处理 data = pd.read_csv( PurePath("../results", date_str), sep='\t', engine='python', encoding='utf-8', converters={'1': parse_list, '2': parse_list, '3': parse_list} ) # 单次遍历全量数据,匹配所有符合条件的分组直接累加词频 for _, row in data.iterrows(): row_target = row['target'] row_code = row['code'] # 遍历所有分类,匹配符合的条件组 for cat_id in cat_ids: if row[cat_id] != 1: continue current_key = (cat_id, row_target, row_code) if current_key not in cond_map: continue # 直接累加三类词频 for w in row['1']: cond_map[current_key]['pos'][w] += 1 for w in row['2']: cond_map[current_key]['neg'][w] += 1 for w in row['3']: cond_map[current_key]['rel'][w] += 1 # ========== 3. 把结果写回top_word_id(如果需要保留原有结构) ========== for idx, row in top_word_id.iterrows(): key = (row['category_code'], row['target'], row['region_code']) res = cond_map[key] top_word_id.at[idx, 'weekly_associated_top_word'] = res['rel'] top_word_id.at[idx, 'weekly_positive_top_word'] = res['pos'] top_word_id.at[idx, 'weekly_negative_top_word'] = res['neg']
性能提升说明
- 修正了原代码统计全量数据的逻辑错误,结果符合预期
- 去掉了1500次重复过滤全量数据的操作,仅需一次遍历即可完成所有分组统计
- 读数据时一次性完成类型转换,避免后续重复判断和调用
ast.literal_eval - 用Python字典做条件查询,读写速度比存DataFrame单元格提升10倍以上
- 整体运行速度预计可提升数十到上百倍,单份5万条数据的处理耗时可降到秒级
内容的提问来源于stack exchange,提问作者Inhyeok Yoo
相关产品推荐
相关产品推荐

