基于两个DataFrame计算句子相似度时的性能优化问题
优化相似度计算的核心方案:从O(N*M)到O(N+M)
你的问题本质是低效的循环和重复计算导致的性能灾难:150万条评论 × 39个主题,嵌套iterrows循环加上每次都调用nlp()处理文本,光是重复计算主题向量就做了150万次——这完全是没必要的开销。下面是针对性的优化步骤,能把运行时间从小时级压缩到分钟级甚至更短:
1. 预计算所有主题的向量(只做一次)
39个主题的关键词是固定的,完全不需要在每次处理评论时重复解析。先一次性把所有主题的向量计算好,存成矩阵:
import numpy as np # 预计算主题向量,仅执行一次 topic_vectors = [] topic_indices = [] for idx, row in topics_words_df.iterrows(): doc = nlp2(row['TopicKeyWords']) if doc.vector_norm: # 保留有效向量 topic_vectors.append(doc.vector) else: # 处理无向量的主题(比如空关键词),用全0向量代替 topic_vectors.append(np.zeros(nlp2.vocab.vectors_length)) topic_indices.append(idx) # 转为numpy矩阵,形状:(39, 向量维度),比如300维 topic_matrix = np.array(topic_vectors)
2. 批量处理评论向量(利用spaCy的pipe)
spaCy的nlp.pipe()是专门为批量文本处理设计的,比逐行调用nlp()快数倍,还支持多进程/CPU加速(GPU会自动适配):
# 批量生成所有评论的向量 comment_vectors = [] # batch_size根据内存调整,n_process=-1用满所有CPU核心 for doc in nlp2.pipe(Post_sent_df['Sent_text'], batch_size=1000, n_process=-1): if doc.vector_norm: comment_vectors.append(doc.vector) else: comment_vectors.append(np.zeros(nlp2.vocab.vectors_length)) # 转为numpy矩阵,形状:(1500000, 向量维度) comment_matrix = np.array(comment_vectors)
3. 用矩阵乘法一次性计算所有相似度
spaCy的similarity()本质是余弦相似度,我们可以用numpy的矩阵运算直接批量计算,这比循环快几个数量级:
# 归一化向量(余弦相似度需要除以向量的L2范数) comment_norm = np.linalg.norm(comment_matrix, axis=1, keepdims=True) topic_norm = np.linalg.norm(topic_matrix, axis=1, keepdims=True) # 避免除以0的情况(全0向量的相似度设为0) comment_norm[comment_norm == 0] = 1 topic_norm[topic_norm == 0] = 1 # 计算相似度矩阵:形状(1500000, 39),每个元素对应一条评论和一个主题的相似度 similarity_matrix = np.dot(comment_matrix / comment_norm, (topic_matrix / topic_norm).T)
4. 把结果合并到原DataFrame
最后把相似度矩阵转成DataFrame,和原表合并即可:
# 生成相似度列,列名对应主题索引 similarity_df = pd.DataFrame( similarity_matrix, columns=topic_indices, index=Post_sent_df.index ) # 合并到原DataFrame Post_sent_df = pd.concat([Post_sent_df, similarity_df], axis=1)
额外优化建议
- GPU加速:如果Colab使用GPU实例,确保安装了GPU版本的spaCy(
pip install spacy[cuda11x]),nlp.pipe()会自动利用GPU,速度再提升数倍。 - 提前过滤无效文本:先清理
Post_sent_df['Sent_text']中的空字符串、纯标点等无效内容,减少不必要的向量计算。 - 内存优化:如果内存不够,可以把评论分成若干块(比如每次处理10万条),分块计算后再合并结果,避免一次性加载150万条向量。
这样优化后,整个流程的时间复杂度从O(N*M)降到O(N+M),运行时间会大幅降低,完全能在Colab中完成任务。
内容的提问来源于stack exchange,提问作者AHmDania
相关产品推荐
相关产品推荐

