文本相似度计算方法全景解析:从 TF-IDF 到 BERT

内容纲要

一、引言

“如何判断两段文本是否表达了相同的意思?”这是 NLP 世界里的“灵魂三问”之一,出现在搜索引擎、智能问答、推荐系统、对话系统等大量场景中。为此,研究者们提出了许多计算文本相似度的方法。从最早的统计词频方法到如今强大的预训练语言模型,每一代技术都有它的独特优势和适用场景。

本文将全面解析主流的文本相似度计算方法,帮助你快速选型并灵活落地。


二、文本相似度的定义与分类

文本相似度主要分为两类:

  1. 语法层面(Shallow Similarity):基于词面、词频统计,如 TF-IDF、Jaccard、编辑距离等。
  2. 语义层面(Semantic Similarity):基于上下文和意义的理解,如 Word2Vec、BERT、Siamese 网络等。

三、主流文本相似度计算方法全景图

方法 类型 是否考虑语义 代表模型或算法 优点 缺点
TF-IDF 词频统计型 TF-IDF 简单高效,可解释性强 无法理解语义
Word2Vec 词嵌入型 CBOW / Skip-gram 能表示词语语义 静态向量,OOV 问题
平均词向量 聚合向量型 Word2Vec/GloVe 快速聚合词语语义 忽略词序、上下文
Siamese 网络 神经结构型 Bi-LSTM/GRU + 对比损失 表示上下文序列语义 训练成本高,需要标注数据
BERT 预训练模型 是(动态) Transformer/BERT 语义理解最强 计算开销大,部署成本高

四、方法逐一剖析与代码示例


1. TF-IDF + 余弦相似度(基准方法)

适用于文本较短,或计算资源有限的场景。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

texts = ["我爱自然语言处理", "自然语言处理是人工智能的分支"]
vec = TfidfVectorizer()
tfidf = vec.fit_transform(texts)

similarity = cosine_similarity(tfidf[0], tfidf[1])
print(f"相似度:{similarity[0][0]:.4f}")

2. Word2Vec 平均向量 + 余弦相似度

每个词转换为向量,取平均表示整个句子。

import numpy as np
from gensim.models import Word2Vec
from sklearn.metrics.pairwise import cosine_similarity

model = Word2Vec([["我", "爱", "自然", "语言", "处理"]], vector_size=100, min_count=1)

def sentence_vector(sentence):
    words = sentence.split()
    vectors = [model.wv[w] for w in words if w in model.wv]
    return np.mean(vectors, axis=0).reshape(1, -1)

vec1 = sentence_vector("我爱自然语言处理")
vec2 = sentence_vector("自然语言处理是人工智能的分支")

sim = cosine_similarity(vec1, vec2)
print(f"相似度:{sim[0][0]:.4f}")

3. Siamese 双塔网络(Bi-LSTM 示例)

适合大规模匹配任务,如搜索召回、意图识别。

思路流程:
输入句对 → 两个共享权重的 Bi-LSTM → 得到句向量 → 计算欧氏距离或余弦相似度 → 相似度评分

框架上常用 Siamese-BERTSentence-BERT 等封装库。下面用 Sentence-BERT 举个例:

from sentence_transformers import SentenceTransformer, util

model = SentenceTransformer('paraphrase-MiniLM-L6-v2')

sentence1 = "我爱自然语言处理"
sentence2 = "自然语言处理是人工智能的重要分支"

embedding1 = model.encode(sentence1, convert_to_tensor=True)
embedding2 = model.encode(sentence2, convert_to_tensor=True)

sim = util.pytorch_cos_sim(embedding1, embedding2)
print(f"相似度:{sim.item():.4f}")

4. BERT CLS 向量 + 相似度计算

使用 BERT 模型的 [CLS] 向量作为句向量进行匹配。

from transformers import BertTokenizer, BertModel
import torch

tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
model = BertModel.from_pretrained('bert-base-chinese')

def get_cls_embedding(text):
    inputs = tokenizer(text, return_tensors='pt', truncation=True, padding=True)
    outputs = model(**inputs)
    return outputs.last_hidden_state[:, 0, :]  # CLS向量

v1 = get_cls_embedding("我爱自然语言处理")
v2 = get_cls_embedding("自然语言处理是人工智能的重要分支")

cos = torch.nn.functional.cosine_similarity(v1, v2)
print(f"相似度:{cos.item():.4f}")

五、选型建议

应用场景 推荐方法
简单关键词相似匹配 TF-IDF + 余弦相似度
通用语义近似、短文本匹配 Word2Vec + 平均向量
大规模语义召回 / 推理任务 Siamese 网络 / SBERT
高质量语义理解、推理 BERT / RoBERTa 等预训练模型

六、总结

文本相似度是一项基础但关键的 NLP 技术。随着预训练语言模型的发展,语义匹配已不再依赖传统规则,而进入了“理解为王”的时代。但 TF-IDF 和 Word2Vec 并未过时,它们在轻量级、快速部署等场景中依然可靠。

作为开发者,我们应当理解每种方法背后的原理、优劣和适用边界,做到“选得准、用得巧”。


引用资料

  1. Reimers, N., & Gurevych, I. (2019). Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. arXiv preprint arXiv:1908.10084
  2. scikit-learn 文档:https://scikit-learn.org/stable/modules/feature_extraction.html
  3. Gensim 文档:https://radimrehurek.com/gensim/models/word2vec.html
  4. Hugging Face Transformers:https://huggingface.co/docs/transformers
  5. Google BERT 原论文:https://arxiv.org/abs/1810.04805

Leave a Comment

您的电子邮箱地址不会被公开。 必填项已用*标注

close
arrow_upward