基于GloVe词嵌入的DataFrame文本列自余弦相似度矩阵高效计算方案咨询
高效计算文本余弦相似度矩阵的方法
嘿,我懂你遇到的痛点——双重apply或者嵌套iterrows循环确实会因为大量重复计算和Python层面的循环开销,导致速度慢到让人抓狂,尤其是当你的DataFrame行数较多的时候。下面给你几个更高效的实现方案,能大幅提升计算效率:
1. 预计算所有文本的GloVe嵌入向量(核心优化)
之前的方法每次计算一对文本的相似度时,都会重复生成两个文本的词嵌入向量,这是最大的性能浪费。我们可以先把所有文本的向量一次性计算好,再批量计算相似度:
import numpy as np import pandas as pd import scipy.spatial.distance as dist # 先定义单个文本转GloVe向量的函数(优化空文本/无有效词的情况) def get_glove_vector(text): processed_words = preprocess(text) # 只保留GloVe词典中存在的词的向量 valid_vectors = [glove[word] for word in processed_words if word in glove] # 处理没有有效词的情况,返回和GloVe向量同维度的0向量 if not valid_vectors: return np.zeros_like(next(iter(glove.values()))) # 返回词向量的均值 return np.mean(valid_vectors, axis=0) # 为DataFrame添加向量列,每个文本只计算一次向量 a['glove_vector'] = a['texts'].apply(get_glove_vector) # 将所有向量堆叠成一个二维矩阵 vectors_matrix = np.vstack(a['glove_vector'].values) # 用scipy的cdist批量计算余弦距离,再转成相似度(1 - 距离) similarity_matrix = 1 - dist.cdist(vectors_matrix, vectors_matrix, metric='cosine') # 转换成以names为索引和列的最终相似度DataFrame similarity_df = pd.DataFrame( similarity_matrix, index=a['names'], columns=a['names'] )
为什么这个方法更快?
- 每个文本的词嵌入向量只计算一次,彻底避免了重复计算;
scipy.spatial.distance.cdist是用C实现的批量计算,比Python层面的循环快几个数量级;- 逻辑更清晰,减少了函数调用的额外开销。
2. 提前预处理所有文本(进一步优化)
如果你的preprocess函数(比如分词、去停用词等)比较耗时,建议先把所有文本的预处理结果存起来,避免重复预处理:
# 先预处理所有文本并存储 a['processed_text'] = a['texts'].apply(preprocess) # 基于预处理后的文本计算向量 def get_vector_from_processed(words): valid_vectors = [glove[word] for word in words if word in glove] if not valid_vectors: return np.zeros_like(next(iter(glove.values()))) return np.mean(valid_vectors, axis=0) a['glove_vector'] = a['processed_text'].apply(get_vector_from_processed) # 后续步骤和上面一致,生成相似度矩阵
3. 超大数据量?试试并行计算
如果你的DataFrame行数特别多(比如上万行),可以用joblib实现并行计算向量,充分利用多核CPU:
from joblib import Parallel, delayed # 并行计算所有文本的向量,n_jobs=-1表示用所有可用核心 vectors_list = Parallel(n_jobs=-1)( delayed(get_glove_vector)(text) for text in a['texts'] ) vectors_matrix = np.vstack(vectors_list) # 后续生成相似度矩阵的步骤不变
内容的提问来源于stack exchange,提问作者Pavlos Panteliadis
相关产品推荐
相关产品推荐

