文本相似度怎么计算?

访客 自然语言处理 1

本文目录导读:

  1. 基于字面匹配(适合短文本、关键词匹配)
  2. 基于词向量与语义(适合中长文本、理解语义)
  3. 面向长文档(适合篇章级比较)
  4. 中文文本的特殊处理
  5. 如何选择?(决策指南)
  6. 代码示例(Python,使用 Sentence-BERT)

计算文本相似度的方法有很多,选择哪种取决于文本的长度(短文本 vs 长文档)、语言(中文 vs 英文)以及对语义理解的要求(字面匹配 vs 语义相似)。

下面从传统方法深度学习/大模型方法,分类介绍几种主流方式:


基于字面匹配(适合短文本、关键词匹配)

这类方法不考虑词义,只计算词汇重叠或字符重叠的比例。

编辑距离(Levenshtein Distance)

  • 原理:把一个字符串变成另一个字符串所需的最少编辑操作(插入、删除、替换)次数。
  • 计算:距离越小,相似度越高,可以归一化:相似度 = 1 - (编辑距离 / 最大长度)
  • 适用:拼写纠错、精准匹配、短文本(如地址、姓名)。
  • 示例“abc”“abd” 编辑距离为 1(替换 c→d)。

Jaccard 相似度

  • 原理:计算两个集合(如分词后的词语集合)的交集大小除以并集大小。
  • 公式J(A, B) = |A ∩ B| / |A ∪ B|
  • 适用:去重、关键词重叠度检查。
  • 示例:句子A:“我喜欢猫” → 词集 {我,喜欢,猫};句子B:“我不喜欢狗”{我,不喜欢,狗} ,交集 {我},并集 {我,喜欢,猫,不喜欢,狗},Jaccard = 1/5 = 0.2。

余弦相似度(基于 TF-IDF)

  • 原理:将文本转为向量(每个词用词频或TF-IDF权重表示),计算两个向量夹角的余弦值,值越接近1,方向越一致。
  • 公式cos(A, B) = (A·B) / (|A| * |B|)
  • 适用:长文档(如文章、论文)的比较,能过滤常见词。
  • 缺点:无法处理同义词(“电脑”和“计算机”会被视为完全不同)。

基于词向量与语义(适合中长文本、理解语义)

这类方法引入预训练的神经网络,能理解“猫”和“狗”都是宠物。

Word2Vec / GloVe 词向量平均

  • 原理:将每个词映射到一个稠密向量(如300维),然后将句子中所有词的向量取平均,得到句子向量,再计算余弦相似度。
  • 优点:比TF-IDF效果好,能捕捉部分语义。
  • 缺点:词向量平均会丢失顺序信息;对否定词不敏感(“不好”可能会被平均成中性)。

句子嵌入模型(Sentence-BERT / SimCSE)

  • 原理:专门用于将整个句子转化为高维语义向量,使用预训练的BERT或RoBERTa模型,通过对比学习训练,使得语义相似的句子向量距离更近。
  • 计算:输入句子A和句子B,直接输出两个向量,计算余弦相似度。
  • 适用目前工业界最常用方法,适合短文本匹配(如问答、搜索query与标题匹配)。
  • 示例:模型会判定“今天天气真好”和“今天是个好天气”相似度很高。

BERT 交叉编码器(Cross-Encoder)

  • 原理:不单独生成向量,而是将两段文本拼接成一个序列输入BERT,由模型直接输出一个0到1的相似度分数。
  • 优点:精度最高,能捕捉词序、否定、指代等复杂关系。
  • 缺点:速度慢,需要两两配对输入,不适合大规模检索(可先用Bi-Encoder检索粗排,再用Cross-Encoder精排)。
  • 适用:精排、语义蕴涵判断(Entailment)。

面向长文档(适合篇章级比较)

LSA / LDA 主题模型

  • 原理:将文档表示为“主题分布”(如:60%体育,30%科技,10%娱乐),然后计算两个主题分布的KL散度或余弦相似度。
  • 适用:新闻聚类、长文档主题相似度。

BM25(信息检索经典算法)

  • 原理:基于概率检索模型,计算文档与查询的相关度,考虑了词频、逆文档频率、文档长度归一化。
  • 适用:搜索引擎召回阶段,计算查询与文档的关键词匹配程度。
  • 特点:不是对称的(query与doc相似度 ≠ doc与query相似度)。

中文文本的特殊处理

中文不像英文天然有空格分词,因此计算前通常需要:

  1. 分词:使用 jiebaHanLPPKUSeg 等工具。“我喜欢北京天安门” → “我 / 喜欢 / 北京 / 天安门”
  2. 去除停用词:去掉“的、了、是、在”等无意义高频词。
  3. 词性标注或实体识别(可选):对关键实体(人名、地名)赋予更高权重。

如何选择?(决策指南)

场景 推荐方法 原因
拼写纠错、DNA序列 编辑距离 精确到字符级
短文本去重(如评论) Jaccard / SimHash 速度快,适合海量数据
搜索引擎召回 BM25 经典、高效、可解释性强
开放域问答匹配 Sentence-BERT 语义理解好,速度快
法律/金融合同比对 编辑距离 + 实体对齐 需要字面上精确匹配改动点
高精度语义相似度 BERT Cross-Encoder 精度最高,但速度慢
大规模聚类 Sentence-BERT + 余弦距离 先编码,再聚类

代码示例(Python,使用 Sentence-BERT)

这是目前最实用的方案之一:

from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
# 1. 加载预训练模型(会自动下载)
# 中文推荐:'shibing624/text2vec-base-chinese' 或 'BAAI/bge-small-zh-v1.5'
model = SentenceTransformer('shibing624/text2vec-base-chinese')
# 2. 定义句子
sentences = [
    "我喜欢看科幻电影",
    "我对科幻片很感兴趣",
    "我今天吃了火锅"
]
# 3. 生成向量
embeddings = model.encode(sentences)
# 4. 计算相似度
sim_12 = cosine_similarity([embeddings[0]], [embeddings[1]])[0][0]  # 结果 ≈ 0.85
sim_13 = cosine_similarity([embeddings[0]], [embeddings[2]])[0][0]  # 结果 ≈ 0.30
print(f"句子1与句子2 相似度: {sim_12:.2f}")
print(f"句子1与句子3 相似度: {sim_13:.2f}")

如果你的需求是简单的字面匹配,用 Jaccard 或 TF-IDF 余弦;如果你需要理解“同义词”和“语义”,用 Sentence-BERTBERT Cross-Encoder(前者速度快,后者精度高)。

标签: 计算方法

抱歉,评论功能暂时关闭!