NLP 文本相似度计算
NLP 文本相似度计算简介
文本相似度计算是自然语言处理(NLP)中的一项关键任务,用于衡量两个或多个文本在语义或语法上的相似程度。它广泛应用于信息检索、推荐系统、问答系统、重复检测等领域。本教程基于 2025 年 10 月的最新技术和 Python 生态(Python 3.10+),介绍文本相似度计算的原理、方法、工具和代码示例,涵盖传统方法和深度学习方法,适合初学者和中级开发者。
1. 文本相似度计算的核心概念
- 定义:量化两个文本之间的相似性,通常输出一个范围在 [0,1] 的分数(1 表示完全相似,0 表示完全不同)。
- 相似性类型:
- 词面相似性:基于词频或字符重叠(如余弦相似度、Jaccard)。
- 语义相似性:基于词义或上下文(如 Word2Vec、BERT 嵌入)。
- 应用场景:
- 信息检索:匹配查询和文档。
- 推荐系统:推荐相似文章或产品描述。
- 文本去重:检测重复或近似文本。
- 流程:
- 预处理:清洗、分词、去除停用词。
- 文本表示:将文本转为向量(如 TF-IDF、BERT 嵌入)。
- 相似度计算:使用度量方法(如余弦相似度)。
2. 常用工具
以下是 2025 年主流的 Python 库,适合文本相似度计算:
- scikit-learn:实现 TF-IDF 和余弦相似度。
- NLTK/spaCy:文本预处理(分词、停用词移除)。
- Gensim:Word2Vec 等词嵌入。
- Sentence Transformers (Hugging Face):生成句子级嵌入,适合语义相似度。
- Transformers (Hugging Face):基于 BERT 的嵌入。
安装命令:
pip install scikit-learn nltk spacy gensim sentence-transformers transformers
python -m spacy download en_core_web_sm # 英语模型
python -m spacy download zh_core_web_sm # 中文模型
3. 文本相似度计算方法
3.1 基于 TF-IDF 的余弦相似度
- 原理:将文本转为 TF-IDF 向量,计算向量间的余弦相似度。
- 优点:简单,适合词面相似性。
- 缺点:忽略语义和词序。
- 公式:
[
\text{cosine similarity} = \frac{A \cdot B}{|A| |B|}
]
其中 (A) 和 (B) 是文本向量。
示例代码:
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import re
import nltk
from nltk.corpus import stopwords
nltk.download(‘stopwords’)
预处理函数
def preprocess_text(text):
text = re.sub(r’http\S+|[^\w\s]’, ”, text) # 移除 URL 和标点
text = re.sub(r’\s+’, ‘ ‘, text).strip() # 移除多余空格
text = text.lower()
stop_words = set(stopwords.words(‘english’))
tokens = text.split()
return ‘ ‘.join([token for token in tokens if token not in stop_words])
测试文本
texts = [
“Apple launches new iPhone in San Francisco.”,
“Samsung introduces Galaxy in New York.”,
“Apple releases iPhone 16 with new features.”
]
texts = [preprocess_text(text) for text in texts]
TF-IDF 向量化
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(texts)
计算余弦相似度
similarity_matrix = cosine_similarity(tfidf_matrix)
输出
for i in range(len(texts)):
for j in range(i + 1, len(texts)):
print(f”文本 {i+1} 和 文本 {j+1} 的相似度: {similarity_matrix[i][j]:.4f}”)
输出示例:
文本 1 和 文本 2 的相似度: 0.2381
文本 1 和 文本 3 的相似度: 0.6765
文本 2 和 文本 3 的相似度: 0.1789
说明:
- 预处理:移除停用词和标点,降低噪声。
- TF-IDF:捕捉词的重要性。
- 余弦相似度:值接近 1 表示更相似。
3.2 基于 Word2Vec 的词嵌入相似度
- 原理:使用 Word2Vec 将词转为密集向量,平均词向量表示句子,计算余弦相似度。
- 优点:捕捉词级语义。
- 缺点:忽略上下文和词序。
示例代码:
from gensim.models import Word2Vec
from nltk.tokenize import word_tokenize
import numpy as np
import nltk
nltk.download(‘punkt’)
预处理函数
def preprocess_text(text):
return word_tokenize(text.lower())
测试文本
texts = [
“Apple launches new iPhone in San Francisco.”,
“Samsung introduces Galaxy in New York.”,
“Apple releases iPhone 16 with new features.”
]
tokenized_texts = [preprocess_text(text) for text in texts]
训练 Word2Vec
model = Word2Vec(sentences=tokenized_texts, vector_size=100, window=5, min_count=1, workers=4)
计算句子向量(平均词向量)
def get_sentence_vector(tokens, model):
vectors = [model.wv[token] for token in tokens if token in model.wv]
return np.mean(vectors, axis=0) if vectors else np.zeros(model.vector_size)
sentence_vectors = [get_sentence_vector(tokens, model) for tokens in tokenized_texts]
计算余弦相似度
def cosine_similarity(vec1, vec2):
return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
输出
for i in range(len(texts)):
for j in range(i + 1, len(texts)):
sim = cosine_similarity(sentence_vectors[i], sentence_vectors[j])
print(f”文本 {i+1} 和 文本 {j+1} 的相似度: {sim:.4f}”)
输出示例(结果因训练随机性而异):
文本 1 和 文本 2 的相似度: 0.7562
文本 1 和 文本 3 的相似度: 0.8923
文本 2 和 文本 3 的相似度: 0.7234
说明:
- Word2Vec:需大量数据训练,实际应用可加载预训练模型(如
gensim.downloader.load('word2vec-google-news-300'))。 - 句子向量:通过平均词向量表示句子。
3.3 基于 Sentence Transformers 的语义相似度
- 原理:使用预训练 Transformer 模型(如 BERT)生成句子级嵌入,计算余弦相似度。
- 优点:捕捉上下文和语义,性能优异。
- 缺点:计算复杂度高。
示例代码:
from sentence_transformers import SentenceTransformer, util
加载预训练模型
model = SentenceTransformer(‘all-MiniLM-L6-v2’)
测试文本
texts = [
“Apple launches new iPhone in San Francisco.”,
“Samsung introduces Galaxy in New York.”,
“Apple releases iPhone 16 with new features.”
]
生成嵌入
embeddings = model.encode(texts, convert_to_tensor=True)
计算余弦相似度
similarity_matrix = util.cos_sim(embeddings, embeddings)
输出
for i in range(len(texts)):
for j in range(i + 1, len(texts)):
print(f”文本 {i+1} 和 文本 {j+1} 的相似度: {similarity_matrix[i][j]:.4f}”)
输出示例:
文本 1 和 文本 2 的相似度: 0.6234
文本 1 和 文本 3 的相似度: 0.9123
文本 2 和 文本 3 的相似度: 0.5876
说明:
- 模型:
all-MiniLM-L6-v2是轻量高效的句子嵌入模型,生成 384 维向量。 - 优势:捕捉深层语义,适合复杂任务。
3.4 中文文本相似度
中文需要专用模型(如 bert-base-chinese)。
示例代码:
from sentence_transformers import SentenceTransformer, util
加载中文模型
model = SentenceTransformer(‘sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2’)
测试文本
texts = [
“苹果在旧金山发布新款iPhone。”,
“三星在纽约推出Galaxy。”,
“苹果发布iPhone 16,新增功能。”
]
生成嵌入
embeddings = model.encode(texts, convert_to_tensor=True)
计算余弦相似度
similarity_matrix = util.cos_sim(embeddings, embeddings)
输出
for i in range(len(texts)):
for j in range(i + 1, len(texts)):
print(f”文本 {i+1} 和 文本 {j+1} 的相似度: {similarity_matrix[i][j]:.4f}”)
输出示例:
文本 1 和 文本 2 的相似度: 0.5987
文本 1 和 文本 3 的相似度: 0.9234
文本 2 和 文本 3 的相似度: 0.5678
说明:paraphrase-multilingual-MiniLM-L12-v2 支持多语言,适合中文任务。
4. 方法比较
| 方法 | 类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| TF-IDF + 余弦 | 稀疏 | 简单、计算快 | 忽略语义 | 词面相似、简单检索 |
| Word2Vec | 密集 | 捕捉词级语义 | 忽略上下文 | 词相似度、初步语义分析 |
| Sentence Transformers | 密集 | 上下文语义、性能强 | 计算复杂 | 语义搜索、复杂任务 |
5. 性能优化技巧
- TF-IDF:
- 限制词汇表:
max_features=5000。 - 使用稀疏矩阵存储(scikit-learn 默认)。
- Word2Vec:
- 加载预训练模型,减少训练时间。
- 降低向量维度(如 100 维)。
- Sentence Transformers:
- 使用轻量模型(如
all-MiniLM-L6-v2)。 - 批量推理:
model.encode(texts, batch_size=32)。 - GPU 加速:确保 PyTorch 支持 CUDA。
- 预处理:
- 缓存嵌入:保存向量到文件(如
pickle)。 - 批量预处理:使用
nlp.pipe()(spaCy)。
6. 注意事项
- 预处理:
- 英文:移除停用词,统一大小写(参考文本预处理教程)。
- 中文:确保分词准确(如 spaCy 或 jieba)。
- 任务需求:
- 词面相似:用 TF-IDF。
- 语义相似:用 Sentence Transformers。
- 语言支持:
- 英文:丰富模型支持。
- 中文:使用
bert-base-chinese或多语言模型。 - 评估:用标准数据集(如 STS-B)验证相似度质量。
7. 进阶学习建议
- 多模态相似度:结合图像(如 CLIP,OpenCV 提取特征)与文本。
- 跨语言相似度:使用
xlm-roberta-base或多语言 Sentence Transformers。 - 实时计算:优化推理速度(如 ONNX 量化)。
- 资源:
- Hugging Face Sentence Transformers:句子嵌入指南。
- scikit-learn 文本处理:TF-IDF 教程。
- CSDN 文本相似度:中文案例。
如果你需要针对特定任务(如中文相似度、实时推荐系统)或更复杂的实现(如跨语言相似度),请告诉我,我可以提供详细代码和指导!