NLP 文本相似度计算

NLP 文本相似度计算简介

文本相似度计算是自然语言处理(NLP)中的一项关键任务,用于衡量两个或多个文本在语义或语法上的相似程度。它广泛应用于信息检索、推荐系统、问答系统、重复检测等领域。本教程基于 2025 年 10 月的最新技术和 Python 生态(Python 3.10+),介绍文本相似度计算的原理、方法、工具和代码示例,涵盖传统方法和深度学习方法,适合初学者和中级开发者。


1. 文本相似度计算的核心概念

  • 定义:量化两个文本之间的相似性,通常输出一个范围在 [0,1] 的分数(1 表示完全相似,0 表示完全不同)。
  • 相似性类型
  • 词面相似性:基于词频或字符重叠(如余弦相似度、Jaccard)。
  • 语义相似性:基于词义或上下文(如 Word2Vec、BERT 嵌入)。
  • 应用场景
  • 信息检索:匹配查询和文档。
  • 推荐系统:推荐相似文章或产品描述。
  • 文本去重:检测重复或近似文本。
  • 流程
  1. 预处理:清洗、分词、去除停用词。
  2. 文本表示:将文本转为向量(如 TF-IDF、BERT 嵌入)。
  3. 相似度计算:使用度量方法(如余弦相似度)。

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. 进阶学习建议

如果你需要针对特定任务(如中文相似度、实时推荐系统)或更复杂的实现(如跨语言相似度),请告诉我,我可以提供详细代码和指导!

类似文章

发表回复

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