NLP学习笔记07:文本相似度计算——从 TF-IDF 到 BERT

NLP学习笔记07:文本相似度计算------从 TF-IDF 到 BERT

作者:Ye Shun

日期:2026-04-17

一、前言

文本相似度计算是自然语言处理(NLP)中的一项基础任务,它的目标是量化两个文本片段之间有多相似。这里的"相似"既可以指表面词汇上的重叠,也可以指语义层面的接近程度。

例如,下面两句话:

  • "苹果发布新款 iPhone 手机"
  • "苹果公司推出最新智能手机"

虽然它们的措辞并不完全相同,但表达的主题高度接近,因此可以认为它们具有较高的文本相似度。

文本相似度在很多系统里都是基础能力,例如:

  • 搜索排序
  • 问答匹配
  • 抄袭检测
  • 推荐系统
  • 文本去重
  • 相似新闻聚合

这篇笔记将围绕以下几个问题展开:

  1. 什么是文本相似度,它有哪些常见类型
  2. 常见的相似度计算方法有哪些
  3. 余弦相似度、欧氏距离等指标分别适合什么场景
  4. 如何通过示例理解短文本相似度计算
  5. 在实际应用中应该如何选择方法

二、核心概念

在讨论方法之前,先要分清文本相似度中几个容易混淆的概念。

1. 字面相似度

字面相似度关注文本在表层词汇上的重叠程度。例如两个句子用了很多相同的词,那么它们的字面相似度通常较高。

这种方法的优点是简单、计算快,但缺点也很明显:它往往无法真正理解语义。

2. 语义相似度

语义相似度关注文本表达的含义是否接近,而不只是看词是不是一样。

例如:

  • "我喜欢自然语言处理"
  • "我很爱学习 NLP 技术"

从词面看,两句话不完全相同;但从语义上看,它们都表达了对 NLP 学习的积极态度,因此语义相似度较高。

3. 向量空间模型

很多文本相似度方法的本质,都是先把文本转换成向量,再在向量空间中计算"距离"或"相似度"。

也就是说,文本相似度通常分两步:

  1. 文本表示
  2. 向量之间的相似度计算

4. 距离与相似度

需要注意,"距离"和"相似度"并不完全一样:

  • 距离越小,通常表示越接近
  • 相似度越大,通常表示越接近

两者可以互相转换,但语义上方向不同。

三、常用文本相似度计算方法

从方法演进上看,文本相似度大致可以分为三类:

  • 基于词频的传统方法
  • 基于词向量的方法
  • 基于预训练语言模型的方法

1. 基于词频的方法

这类方法的核心特点是:先统计词在文本中的出现情况,再据此构造向量。

词袋模型(Bag of Words)

词袋模型把文本看成词的集合,不考虑顺序,只统计词出现与否或出现次数。

示例:

python 复制代码
from sklearn.feature_extraction.text import CountVectorizer

corpus = [
    "我 喜欢 自然语言处理",
    "我 爱 学习 NLP 技术",
    "文本 相似度 计算 很 有趣"
]

vectorizer = CountVectorizer(token_pattern=r"(?u)\b\w+\b")
X = vectorizer.fit_transform(corpus)
print(X.toarray())

这种方法简单直观,但它的问题也很明显:

  • 忽略词序
  • 忽略语义
  • 向量维度高且稀疏
TF-IDF 方法

TF-IDF 是词袋模型的改进版。它不仅考虑词频,还考虑一个词在整个语料中的区分能力。

如果一个词在所有文本里都频繁出现,那么它对区分文本的帮助就较小;而某些只在少数文本中出现的词,往往更能反映文本特点。

示例:

python 复制代码
from sklearn.feature_extraction.text import TfidfVectorizer

tfidf = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b")
tfidf_matrix = tfidf.fit_transform(corpus)
print(tfidf_matrix.toarray())

TF-IDF 在信息检索、长文档相似度计算、文本去重等任务中仍然非常常见,因为它简单、高效,而且在很多场景下效果并不差。

2. 基于词向量的方法

传统词频方法能反映词重叠,但难以表示真正的语义相似。词向量方法的目标,就是让语义相近的词在向量空间中也更接近。

Word2Vec

Word2Vec 是经典的词向量方法,它通过上下文学习词语的分布式表示。

示例:

python 复制代码
from gensim.models import Word2Vec

sentences = [
    ["我", "喜欢", "自然语言处理"],
    ["我", "爱", "学习", "NLP", "技术"],
    ["文本", "相似度", "计算", "很", "有趣"]
]

model = Word2Vec(sentences, vector_size=100, window=5, min_count=1, workers=4)
vector = model.wv["自然语言处理"]

相比词袋模型,词向量的优势在于:

  • 维度更低
  • 向量更稠密
  • 能表达一定的语义接近性
句子向量

如果要比较两句话,仅有词向量还不够,通常还需要把整句话表示成一个向量。最简单的方法就是对句中所有词向量取平均。

示例:

python 复制代码
import numpy as np

def sentence_vector(sentence, model):
    vectors = [model.wv[word] for word in sentence if word in model.wv]
    return np.mean(vectors, axis=0) if vectors else np.zeros(model.vector_size)

这种方式实现简单,但问题在于:

  • 它把词的重要性看得差不多
  • 无法很好建模词序
  • 对一词多义处理有限

3. 基于预训练模型的方法

随着预训练语言模型的发展,文本相似度计算已经越来越多地依赖 BERT、Sentence-BERT 等模型。

BERT 相似度

BERT 的核心优势在于它能利用上下文生成动态表示,因此更适合处理语义相似度,而不只是词面重叠。

例如:

python 复制代码
from transformers import BertTokenizer, BertModel
import torch

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

inputs = tokenizer("这是一个示例句子", return_tensors="pt")
outputs = model(**inputs)
last_hidden_states = outputs.last_hidden_state

不过,严格来说,直接拿 BERT 的输出做句子相似度并不是最优实践。现在更常见的做法是使用专门做句向量优化的模型,例如 Sentence-BERT。

为什么预训练模型更强

预训练模型的优势在于:

  • 能更好处理同义表达
  • 能缓解一词多义问题
  • 对短文本语义匹配更有效

但代价是:

  • 计算成本更高
  • 部署复杂度更高

四、常见相似度度量指标

当文本已经被表示成向量之后,下一步就是计算两个向量之间的接近程度。常见指标如下:

方法名称 公式思路 特点
余弦相似度 比较向量方向夹角 忽略长度,最常用
欧氏距离 比较两点的直线距离 关注绝对位置差异
曼哈顿距离 各维绝对差之和 对异常值相对稳定
Jaccard 相似度 交集 / 并集 适合集合或关键词重叠

1. 余弦相似度

余弦相似度是文本相似度中最常见的指标。它比较的是两个向量的方向,而不是绝对长度。

python 复制代码
from sklearn.metrics.pairwise import cosine_similarity

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

之所以常用,是因为很多文本向量本身长度差异较大,而我们更关心它们表达方向是否一致。

2. 欧氏距离与曼哈顿距离

这两类指标更偏"距离"思路,适合在某些嵌入空间或数值特征空间中做比较。但在文本任务里,相比余弦相似度,它们通常没那么常用。

3. Jaccard 相似度

Jaccard 相似度更适合比较两个集合之间的重叠程度,比如两个文本分词后的词集合有多少交集。

它的优点是简单直观,但缺点也很明显:对语义理解能力弱。

五、实践应用示例:新闻标题相似度检测

假设有一组新闻标题:

python 复制代码
titles = [
    "苹果发布新款 iPhone 手机",
    "苹果公司推出最新智能手机",
    "微软公布季度财报",
    "谷歌宣布新的人工智能计划"
]

如果使用 TF-IDF + 余弦相似度计算相似度矩阵,就可能得到类似结果:

标题 苹果发布新款 iPhone 手机 苹果公司推出最新智能手机 微软公布季度财报 谷歌宣布新的人工智能计划
苹果发布新款 iPhone 手机 1.000000 0.723417 0.000000 0.000000
苹果公司推出最新智能手机 0.723417 1.000000 0.000000 0.000000
微软公布季度财报 0.000000 0.000000 1.000000 0.204598
谷歌宣布新的人工智能计划 0.000000 0.000000 0.204598 1.000000

从这个例子可以看出:

  • 前两条标题主题接近,因此相似度高
  • 与微软和谷歌相关的标题主题差异较大,因此相似度低

这类方法非常适合:

  • 相似新闻聚类
  • 标题去重
  • 内容推荐初筛

六、进阶技术与挑战

文本相似度看起来像一个简单任务,但真正做好并不容易。

1. 语义相似但词汇不同

例如:

  • "我喜欢猫"
  • "我讨厌狗"

表面上它们都涉及动物,因此某些浅层方法可能误判为相似;但从情感和语义角度看,它们表达的意思并不接近。

2. 一词多义问题

例如:

  • "苹果很甜"
  • "苹果市值创新高"

这里"苹果"一个表示水果,一个表示公司。传统词频方法很难处理这种情况,而上下文模型会更有优势。

3. 长文本相似度

对于长文档,相似度计算会面临:

  • 信息冗余
  • 局部主题差异
  • 句间重要性不同

这时往往不能只靠简单平均,还需要更复杂的段落表示、句向量聚合或检索式匹配方法。

4. 计算效率问题

在大规模系统中,如果要比较成千上万甚至上百万条文本,两两计算相似度会非常耗时。因此往往需要:

  • 向量索引
  • 近似最近邻(ANN)
  • Faiss 等高效相似度搜索工具

七、最佳实践建议

1. 先做好数据预处理

很多相似度效果问题,最后都能追溯到预处理不到位。例如:

  • 大小写不统一
  • 停用词影响过大
  • 中文没有合理分词
  • 文本噪声过多

2. 根据场景选择方法

可以做一个大致的经验判断:

  • 短文本语义匹配:更适合 BERT / Sentence-BERT
  • 长文档初筛:TF-IDF + 余弦相似度 仍然很好用
  • 实时轻量系统:Word2Vec 或更轻量的句向量方法更合适

3. 同时考虑效果和效率

实际系统中,不一定一上来就用最重的模型。很多时候会采用两阶段策略:

  1. 先用 TF-IDF 或轻量向量做粗筛
  2. 再用更强的语义模型做精排

4. 建立评估集并持续优化

文本相似度的好坏往往和具体场景强相关,因此最好建立人工标注的相似度评估集,定期检查模型效果。

八、学习资源建议

如果想继续深入,比较值得看的资源包括:

  • Gensim 官方文档
  • Hugging Face Transformers 文档
  • Scikit-learn 文本处理教程
  • Transformer 论文《Attention Is All You Need》
  • BERT 论文《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》

这里需要顺手纠正一个常见误区:Attention Is All You Need 是 Transformer 的原始论文,不是 BERT 论文;BERT 对应的是另一篇专门论文。

九、总结

文本相似度计算是 NLP 中非常基础但又极其实用的能力。它的核心流程可以概括为:

  1. 把文本表示成向量
  2. 选择合适的相似度度量方式
  3. 根据具体场景平衡效果和效率

从方法演进来看:

  • 词袋模型和 TF-IDF 适合做字面层面的相似度计算
  • Word2Vec 等词向量方法开始引入语义信息
  • BERT 和 Sentence-BERT 等预训练模型则把文本相似度推进到更强的语义匹配阶段

在真正的工程实践中,没有哪种方法能一招通吃。理解不同方法的能力边界,并根据任务场景做组合,往往比单纯追求"最新模型"更重要。

相关推荐
海海不掉头发3 小时前
【AI大模型学习基础篇】小白入门大模型全流程:从训练到MCP智能体
人工智能·python·深度学习·学习·语言模型·自然语言处理·numpy
在学了加油3 小时前
ResNet-50学习笔记
笔记·学习
zhangrelay3 小时前
蓝桥云课一分钟-通关电路仿真-SimulIDE
笔记·学习
阿杰学AI3 小时前
AI核心知识126—大语言模型之 CrewAI 和 AutoGen(简洁且通俗易懂版)
人工智能·语言模型·自然语言处理·agent·多智能体·智能体·多智能体协作框架
Sss_Ass3 小时前
跟着老师不迷路系列——跟着李述铜老师学习汇编语言之基本汇编程序section指令
学习·学习方法·汇编语言·李述铜·section指令
南無忘码至尊3 小时前
Unity学习90天-第7天-学习委托与事件(简化版)
学习·unity·游戏引擎
.小小陈.3 小时前
深度拆解 Linux 进程间通信(IPC):从管道到 System V 全链路详解
linux·服务器·网络·学习
Sss_Ass3 小时前
跟着老师不迷路系列---跟着李述铜老师学习汇编语言之基本汇编程序指令集分类
开发语言·学习·学习方法·汇编语言·李述铜
财经资讯数据_灵砚智能3 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年4月17日
人工智能·python·信息可视化·自然语言处理·ai编程