You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何加速Pandas处理5000万行Spacy句子相似度计算任务?

问题

尝试用Spacy计算两组问题的句子相似度,再通过Pandas输出包含3列的DataFrame(样本问题、用户输入、相似度分数),预计生成约5000万行数据,已运行12小时仍未完成。

小数据集测试时代码正常,但大数据集处理极慢,相关代码如下:

import spacy
import pandas as pd

# 假设已加载nlp模型,例如 nlp = spacy.load("de_core_news_md")
user_inputs_vector = [nlp(row) for row in user_inputs_df["User_Input"]] # 向量化用户输入
sample_df_vector = [nlp(row) for row in sample_df["Frage"]] # 向量化样本句子

# 嵌套循环计算相似度并收集结果
similarity_score_list = [] 
sample_list = [] 
user_input_list = []

for i in range (len(sample_df_vector)):
    for j in range (len(user_inputs_vector)):    
        similar_frage = user_inputs_vector[j].similarity(sample_df_vector[i])
        similarity_score_list.append(similar_frage)
        sample_list.append(sample_df_vector[i])
        user_input_list.append(user_inputs_vector[j])
        similarity_dataframe = pd.DataFrame(list(zip(sample_list, user_input_list, similarity_score_list)), columns = ["Samples", "User Inputs", "Similarity Score"])
加速方案

1. 移除循环内的DataFrame创建

原代码每次循环都重新生成DataFrame,反复触发内存分配与数据拷贝,是核心性能浪费点。将DataFrame创建移到循环结束后:

similarity_score_list = [] 
sample_list = [] 
user_input_list = []

for i in range(len(sample_df_vector)):
    sample_doc = sample_df_vector[i]
    sample_text = sample_doc.text  # 存储文本而非Doc对象,大幅节省内存
    for j in range(len(user_inputs_vector)):    
        user_doc = user_inputs_vector[j]
        similar_frage = user_doc.similarity(sample_doc)
        similarity_score_list.append(similar_frage)
        sample_list.append(sample_text)
        user_input_list.append(user_doc.text)

# 循环结束后一次性创建DataFrame
similarity_dataframe = pd.DataFrame(
    list(zip(sample_list, user_input_list, similarity_score_list)),
    columns=["Samples", "User Inputs", "Similarity Score"]
)

2. 用矩阵运算替代嵌套循环(核心优化)

Spacy的Doc对象可通过.vector提取向量,转为numpy矩阵后用矩阵乘法一次性计算所有相似度,时间复杂度从O(NM)降至O(NK + K*M)(K为向量维度),速度提升几个数量级:

import numpy as np

# 提取所有样本和用户输入的向量,转为numpy矩阵
sample_vectors = np.array([doc.vector for doc in sample_df_vector])
user_vectors = np.array([doc.vector for doc in user_inputs_vector])

# 计算余弦相似度:(用户向量 @ 样本向量转置) / (用户向量模长 @ 样本向量模长转置)
user_norms = np.linalg.norm(user_vectors, axis=1, keepdims=True)
sample_norms = np.linalg.norm(sample_vectors, axis=1, keepdims=True)
similarity_matrix = (user_vectors @ sample_vectors.T) / (user_norms @ sample_norms.T)

# 将矩阵转为长格式DataFrame
sample_texts = sample_df["Frage"].tolist()
user_texts = user_inputs_df["User_Input"].tolist()

# 生成所有配对的索引并扁平化
sample_indices, user_indices = np.meshgrid(range(len(sample_texts)), range(len(user_texts)))

similarity_dataframe = pd.DataFrame({
    "Samples": np.array(sample_texts)[sample_indices.flatten()],
    "User Inputs": np.array(user_texts)[user_indices.flatten()],
    "Similarity Score": similarity_matrix.flatten()
})

3. 内存优化:分块处理或直接写CSV

5000万行数据会占用大量内存(按每行100字节计算约5GB),若内存不足,建议分块处理并直接写入CSV,避免一次性加载所有数据:

chunk_size = 1000  # 根据内存容量调整块大小
with open("similarity_results.csv", "w", encoding="utf-8") as f:
    # 写入表头
    f.write("Samples,User Inputs,Similarity Score\n")
    for i in range(0, len(sample_vectors), chunk_size):
        sample_chunk = sample_vectors[i:i+chunk_size]
        sample_text_chunk = sample_texts[i:i+chunk_size]
        # 计算当前块的相似度矩阵
        chunk_norms = np.linalg.norm(sample_chunk, axis=1, keepdims=True)
        chunk_similarity = (user_vectors @ sample_chunk.T) / (user_norms @ chunk_norms.T)
        # 生成当前块的配对数据并写入文件
        chunk_sample_indices, chunk_user_indices = np.meshgrid(range(len(sample_text_chunk)), range(len(user_texts)))
        for s_idx, u_idx, score in zip(chunk_sample_indices.flatten(), chunk_user_indices.flatten(), chunk_similarity.flatten()):
            # 转义引号避免CSV格式错误
            s_text = sample_text_chunk[s_idx].replace('"', '""')
            u_text = user_texts[u_idx].replace('"', '""')
            f.write(f'"{s_text}","{u_text}",{score}\n')

4. 优化文本向量化过程

使用Spacy的nlp.pipe批量处理文本,比逐个调用nlp(row)更快,还可开启多进程加速:

# batch_size:每次批量处理的文本数量;n_process=-1:使用所有CPU核心
user_inputs_vector = list(nlp.pipe(user_inputs_df["User_Input"], batch_size=512, n_process=-1))
sample_df_vector = list(nlp.pipe(sample_df["Frage"], batch_size=512, n_process=-1))

内容的提问来源于stack exchange,提问作者klam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 22:15:54