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

如何降低Python中行式相似度比较的计算与存储负担?

文本相似度分组优化问题

现有如下DataFrame:

message
0       ABC
1       abc
2       cba
3      abcd
4      dcsa
5      adcd
6      abcd
7       cba                   

需求是对每行文本执行相似度比较,最终基于相似度向量分组计算指标。当前采用暴力法:每行与所有行(含自身)比较,相似度达标记1,否则记0,生成长度为N的相似度向量,复杂度为O(N²)。该方法仅适用于小数据集,无法适配百万级规模数据(每行需存储百万级向量,存储和计算成本极高)。

现寻求以下两个问题的解决方案:

  1. 如何降低O(N²)的计算复杂度?目前尝试对message列排序后缩小比较范围,但会导致各行列的相似度向量长度不一致,无法直接用于分组。
  2. 是否有更高效的相似度信息存储方式?因分组需求必须保留关联信息,能否用其他方式替代全量相似度向量?

可复现最小示例

import pandas as pd
from difflib import SequenceMatcher

df = pd.DataFrame({'message': ['ABC', 'ABCD', 'DCBA', 'abcde', 'CBDA', 'abcde', 'edcba']})

def similarity_score(s1, s2):
    coef = SequenceMatcher(None, s1, s2).ratio()
    return 1 if coef >= 0.75 else 0

def similarity(x, df):
    sim_score = []
    for i in df['message']:
        sim_score.append(similarity_score(x, i))
    return sim_score

df['similarity'] = df['message'].apply(lambda x: similarity(x, df)).astype(str)

需求动机示例(含cnt字段分组汇总)

代码实现

import pandas as pd
from difflib import SequenceMatcher

df = pd.DataFrame({'message': ['ABC','abc','cba','abcd','dcsa','adcd','abcd','cba'], 
                  'cnt': [1, 2, 3, 4, 5, 6, 7, 8]})

def similarity_score(s1, s2):
    coef = SequenceMatcher(None, s1, s2).ratio()
    return 1 if coef >= 0.80 else 0

def similarity(x,df):
    sim_score = []
    for i in df['message']:
        sim_score.append(similarity_score(x, i))
    return sim_score

df['similarity'] = df['message'].apply(lambda x: similarity(x, df)).astype(str)
df["group"] = pd.factorize(df["similarity"].astype(str))[0] + 1
print(df)

输出结果

message  cnt         similarity  group
0     ABC    1  [1, 0, 0, 0, 0, 0, 0, 0]      1
1     abc    2  [0, 1, 0, 1, 0, 0, 1, 0]      2
2     cba    3  [0, 0, 1, 0, 0, 0, 0, 1]      3
3    abcd    4  [0, 1, 0, 1, 0, 0, 1, 0]      2
4    dcsa    5  [0, 0, 0, 0, 1, 0, 0, 0]      4
5    adcd    6  [0, 0, 0, 0, 0, 1, 0, 0]      5
6    abcd    7  [0, 1, 0, 1, 0, 0, 1, 0]      2
7     cba    8  [0, 0, 1, 0, 0, 0, 0, 1]      3

按group汇总cnt

df_final = df.groupby("group").sum("cnt")
print(df_final)

汇总输出

cnt
group     
1        1
2       13
3       11
4        5
5        6

解决方案

问题1:降低O(N²)复杂度

核心思路是避免全量两两比较,通过文本特征预分组+组内精细比较的方式减少计算量:

  • 文本特征哈希/聚类前置:先对文本提取低维特征(如n-gram哈希、TF-IDF向量、Sentence-BERT嵌入),用近似最近邻(ANN)算法(如FAISS、Annoy)快速找到候选相似文本,仅与候选集比较,而非全量数据,复杂度可降至O(N*logN)。
  • 基于文本属性过滤:先按文本长度分组,仅在相同/相近长度的组内做相似度比较(比如长度差≤2的文本才可能达到0.8以上的SequenceMatcher相似度),直接排除大量不可能达标的文本。
  • 排序后滑动窗口比较:对文本按字典序排序后,仅在滑动窗口内(如前后100行)做比较,同时记录原始索引,最后映射回原数据生成统一长度的相似度向量(未比较的行标记为0)。

问题2:替代全量相似度向量的存储与分组方式

不需要存储全量0-1向量,可通过等价类分组直接实现相同的分组效果:

  • 连通分量分组:将相似度达标(≥阈值)的文本对视为图中的边,文本作为节点,用Union-Find(并查集)算法找出所有连通分量,同一个连通分量的文本即为同一组。这种方式仅需记录每个节点的根节点,存储复杂度为O(N),结合问题1的候选集优化可避免全量建边。
  • 特征哈希分组:对文本提取稳定的相似特征(如归一化后的n-gram集合、去重排序后的字符序列),将相同特征的文本归为一组。比如把"abc"和"cba"转为小写后排序字符得到"abc",直接按该特征分组。
  • 聚类标签替代向量:用文本嵌入做聚类(如K-Means、DBSCAN),聚类标签直接作为分组依据,无需存储相似度向量。若需要更精细的分组,可在聚类簇内再做相似度过滤调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 08:57:26