嵌套for循环随运行时间变慢如何优化?700万条推文语料处理场景
性能下降原因
- 核心原因是
pd.DataFrame.append操作的低效率:pandas的DataFrame是不可变结构,每次调用append都会将整个已有data对象全量复制到新的内存空间生成新DataFrame,随着匹配结果越来越多,单次append的耗时会线性增长,90万次迭代后data已经积累了大量数据,复制开销暴涨直接导致处理速度骤降。 - 嵌套循环的冗余开销:代码时间复杂度为O(语料数*关键词数),700万条语料叠加任意数量的关键词都会产生海量重复计算;同时每次匹配调用
re.findall会扫描全句返回所有匹配结果,你仅需要判断是否存在匹配的场景下完全属于算力浪费。 - 循环内频繁
print(n)的IO操作、每次匹配新建临时DataFrame的操作,也会进一步拖慢运行速度。
该问题和内存分配直接相关:每次append都需要申请连续内存存储更大的DataFrame,旧对象频繁被回收会导致内存碎片化,进一步加重内存分配的 overhead。
可行优化方案
- 替换增量append逻辑:先将匹配结果存入普通Python列表,所有遍历完成后一次性转为DataFrame。Python列表的append是均摊O(1)操作,没有全量复制的开销。
- 优化匹配逻辑:
- 无正则匹配需求时直接用
word in sent判断存在性,速度是re.findall的5~10倍;如果确实需要正则匹配,提前把所有关键词预编译为re.compile对象,避免循环中重复编译正则。 - 仅需要判断是否存在匹配时用
re.search替代re.findall,匹配到第一个结果就会停止扫描,减少无效计算。 - 关键词量较大时可以引入Aho-Corasick多模式匹配算法,一次性在单条推文中匹配所有关键词,时间复杂度降到O(语料总长度+关键词总长度),性能会有数量级提升。
- 无正则匹配需求时直接用
- 移除冗余操作:删掉逐行打印逻辑,改为每1万/10万条打印一次进度,降低IO开销;取消每次匹配新建临时DataFrame的操作,直接把结果元组存入列表即可。
优化后参考代码:
import pandas as pd import re # 提前预处理关键词,预编译正则(如果不需要正则匹配可以直接存原始字符串) pattern_info = [ (re.compile(word), tag1, tag2, word) for word, tag1, tag2 in zip(words['token'], words['subtype_I'], words['subtype_II']) ] result_list = [] progress_step = 10000 for n, sent in enumerate(corpus): for pattern, tag1, tag2, word in pattern_info: if pattern.search(sent): result_list.append((sent, tag1, tag2, word)) # 按需打印进度 if n % progress_step == 0: print(f"已处理{n}条语料") # 一次性生成最终DataFrame data = pd.DataFrame(result_list, columns=['testo', 'type', 'type_2','trigger'])
内容的提问来源于stack exchange,提问作者Leonardo Sanna
相关产品推荐
相关产品推荐

