Pandas多DataFrame遍历计算相似词数速度慢,求优化方案
哇,10k×3k的双重循环确实会慢到让人崩溃——3000万次Python级别的迭代,单线程扛不住太正常了。我来给你几个实打实的优化方案,从简单到进阶都有,保证能把速度提上去几个数量级!
先说说原代码慢的核心原因
- 双重Python循环:Python的for循环本身就比底层语言慢,嵌套循环直接把复杂度拉到O(N*M),3000万次重复操作肯定卡。
- 重复的集合转换:每次循环都把
text_tokenized的列表转成集合,完全是做无用功——这些转换只需要做一次就行。 - 低效的DataFrame构建:逐行创建字典再拼接小DataFrame,pandas每次拼接都要重新分配内存,开销极大。
方案1:预转换集合 + 列表推导式(快速见效,代码改动小)
先把两个DataFrame的所有行都预转成集合,然后用列表推导式替代嵌套循环——列表推导式是Python层面最接近底层速度的循环方式。
import pandas as pd # 预转换所有tokenized文本为集合,只做一次! set_list1 = data['text_tokenized'].apply(set).tolist() set_list2 = data2['text_tokenized'].apply(set).tolist() codes = data['code'].tolist() # 用列表推导式计算相似度矩阵,比嵌套for循环快N倍 similarity_matrix = [[len(s1 & s2) for s2 in set_list2] for s1 in set_list1] # 一次性生成结果DataFrame,避免逐行拼接 result_df = pd.DataFrame( similarity_matrix, columns=[f"df2_row_{idx}" for idx in range(len(set_list2))] ) result_df['code'] = codes # 把code列放到最前面 result_df = result_df[['code'] + result_df.columns[:-1].tolist()]
这个方案至少能把速度提升5-10倍,因为预转换避免了重复计算,列表推导式比嵌套循环高效得多。
方案2:CountVectorizer + 矩阵点积(速度天花板,适合大数据)
如果想追求极致速度,就用向量化运算——把文本转换成布尔矩阵,然后用numpy的点积计算交集数量(二进制矩阵的点积就是两个向量共同词的数量)。这种方法用的是C底层运算,速度比Python循环快几十甚至上百倍。
import pandas as pd from sklearn.feature_extraction.text import CountVectorizer # 把tokenized列表转成空格分隔的字符串(CountVectorizer需要输入字符串) data_texts = data['text_tokenized'].apply(lambda x: ' '.join(x)) data2_texts = data2['text_tokenized'].apply(lambda x: ' '.join(x)) # 初始化二进制CountVectorizer:每个词出现标记为1,不统计出现次数 vec = CountVectorizer(binary=True) # 拟合所有文本,得到统一的词汇表 all_texts = pd.concat([data_texts, data2_texts]) vec.fit(all_texts) # 转换为布尔矩阵(形状分别是(10000, 词汇量)和(3000, 词汇量)) data_matrix = vec.transform(data_texts).toarray() data2_matrix = vec.transform(data2_texts).toarray() # 矩阵点积直接得到相似度矩阵(每个元素就是相似词的数量) similarity_matrix = data_matrix @ data2_matrix.T # 生成结果DataFrame result_df = pd.DataFrame( similarity_matrix, columns=[f"df2_row_{idx}" for idx in range(data2.shape[0])] ) result_df['code'] = data['code'].values result_df = result_df[['code'] + result_df.columns[:-1].tolist()]
这个方案的速度取决于词汇表大小,如果词汇量不是特别夸张(比如几万级),处理10k×3k的数据可能只需要几秒到几十秒,比原代码快几百倍都有可能。
方案3:多进程并行处理(超大数据量救星)
如果你的数据量还在往上走,比如10万行×5千行,那可以用多进程把任务拆分到多个CPU核心上,进一步压榨硬件性能。
import pandas as pd import multiprocessing as mp # 预转换集合 set_list1 = data['text_tokenized'].apply(set).tolist() set_list2 = data2['text_tokenized'].apply(set).tolist() codes = data['code'].tolist() # 定义单个行的处理函数 def calculate_row_similarity(s1): return [len(s1 & s2) for s2 in set_list2] # 用CPU全部核心创建进程池 with mp.Pool(mp.cpu_count()) as pool: similarity_matrix = pool.map(calculate_row_similarity, set_list1) # 生成结果DataFrame result_df = pd.DataFrame( similarity_matrix, columns=[f"df2_row_{idx}" for idx in range(len(set_list2))] ) result_df['code'] = codes result_df = result_df[['code'] + result_df.columns[:-1].tolist()]
这个方案的速度提升倍数大概等于你的CPU核心数(比如8核就能快8倍左右),适合处理超大规模的数据集。
内容的提问来源于stack exchange,提问作者Rick Bruins
相关产品推荐
相关产品推荐

