news 2026/5/24 4:50:02

手把手教你用Python搞定文本相似度:从TF-IDF到Sentence-BERT的5个代码实例(附数据集)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手把手教你用Python搞定文本相似度:从TF-IDF到Sentence-BERT的5个代码实例(附数据集)

5种Python文本相似度实战:从基础算法到深度语义匹配

文本相似度计算是自然语言处理中最实用的技术之一。想象一下,你正在开发一个智能客服系统,需要自动识别用户问题与知识库中已有问题的匹配程度;或者你正在构建一个内容推荐引擎,希望找到与用户刚阅读文章最相关的其他内容。这些场景的核心都是文本相似度计算。

1. 环境准备与数据集

在开始之前,我们需要准备一个标准数据集来评估不同算法的效果。对于中文文本相似度计算,LCQMC(Large-scale Chinese Question Matching Corpus)是一个不错的选择,它包含超过26万对中文问题对,每对都有是否相似的标注。

# 安装必要库 !pip install scikit-learn python-Levenshtein gensim sentence-transformers # 下载LCQMC数据集示例 import pandas as pd url = "https://raw.githubusercontent.com/liuhuanyong/ChineseSemanticKB/master/data/LCQMC_train.csv" data = pd.read_csv(url, sep='\t', names=['text1', 'text2', 'label']) sample_data = data.sample(5) # 随机选取5对示例 print(sample_data)

常用评估指标

  • 准确率(Accuracy)
  • F1分数
  • 召回率(Recall)
  • 计算时间(对于实时系统很重要)

2. 传统文本相似度方法

2.1 TF-IDF与余弦相似度

TF-IDF是文本处理中最经典的向量化方法,它考虑了词频(TF)和逆文档频率(IDF),能够有效降低常见词的权重。

from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity texts = ["我喜欢吃苹果", "苹果公司发布了新产品", "香蕉和苹果都是水果"] # 创建TF-IDF向量器 vectorizer = TfidfVectorizer() tfidf_matrix = vectorizer.fit_transform(texts) # 计算相似度矩阵 similarity_matrix = cosine_similarity(tfidf_matrix) print("TF-IDF余弦相似度矩阵:\n", similarity_matrix)

适用场景:短文本快速匹配,如搜索引擎查询、文档去重等。

2.2 编辑距离(Levenshtein Distance)

编辑距离衡量两个字符串之间的最小编辑操作次数,适用于拼写检查、OCR纠错等场景。

from Levenshtein import distance str1 = "kitten" str2 = "sitting" edit_dist = distance(str1, str2) max_len = max(len(str1), len(str2)) similarity = 1 - (edit_dist / max_len) print(f"编辑距离: {edit_dist}") print(f"标准化相似度: {similarity:.2f}")

注意:编辑距离对字符顺序敏感,"苹果手机"和"手机苹果"会被认为差异很大。

3. 词向量方法

3.1 Word2Vec平均词向量

Word2Vec能够捕捉词语的语义信息,我们可以通过平均词向量来表示整个句子。

import gensim.downloader as api import numpy as np # 加载预训练的中文Word2Vec模型 wv = api.load('word2vec-google-news-300') # 示例使用英文模型 def sentence_similarity(s1, s2): vec1 = np.mean([wv[word] for word in s1.split() if word in wv], axis=0) vec2 = np.mean([wv[word] for word in s2.split() if word in wv], axis=0) return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2)) text1 = "king queen palace" text2 = "monarch castle" print(f"Word2Vec相似度: {sentence_similarity(text1, text2):.4f}")

局限性

  • 无法处理OOV(词表外)词语
  • 简单平均会丢失词序信息
  • 对多义词处理不佳

3.2 使用Sentence-BERT进行语义匹配

Sentence-BERT(SBERT)通过孪生网络结构直接生成句子级别的嵌入表示,在语义相似度任务上表现优异。

from sentence_transformers import SentenceTransformer, util # 加载预训练的中文SBERT模型 model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2') sentences = [ "如何重置我的密码", "忘记密码怎么办", "今天的天气真好" ] # 编码所有句子 embeddings = model.encode(sentences) # 计算相似度 sim_matrix = util.cos_sim(embeddings, embeddings) print("SBERT相似度矩阵:\n", sim_matrix)

性能对比

方法准确率计算速度内存占用
TF-IDF中等
编辑距离很快很低
Word2Vec中高中等
SBERT较慢

4. 实战:构建文本相似度系统

让我们整合这些方法,构建一个完整的文本相似度分析流程。

class TextSimilarityAnalyzer: def __init__(self, method='sbert'): self.method = method if method == 'sbert': self.model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2') elif method == 'tfidf': self.vectorizer = TfidfVectorizer() def fit(self, texts): if self.method == 'tfidf': self.vectorizer.fit(texts) def similarity(self, text1, text2): if self.method == 'sbert': emb1 = self.model.encode(text1) emb2 = self.model.encode(text2) return util.cos_sim(emb1, emb2).item() elif self.method == 'tfidf': vecs = self.vectorizer.transform([text1, text2]) return cosine_similarity(vecs[0], vecs[1])[0][0] elif self.method == 'edit': max_len = max(len(text1), len(text2)) return 1 - (distance(text1, text2) / max_len) # 使用示例 analyzer = TextSimilarityAnalyzer(method='sbert') text_a = "如何开通网上银行" text_b = "网上银行怎么申请" print(f"相似度得分: {analyzer.similarity(text_a, text_b):.2f}")

优化技巧

  • 对于大规模数据,可以先使用TF-IDF快速筛选候选集,再用SBERT精细匹配
  • 可以组合多种相似度得分进行加权融合
  • 对于特定领域,可以微调SBERT模型

5. 高级应用与挑战

5.1 处理长文档相似度

对于长文档,直接使用上述方法效果可能不佳。常见的解决方案包括:

  1. 分块处理:将文档分成段落或句子,分别计算相似度后聚合
  2. 关键信息提取:先抽取关键词、主题或摘要,再计算相似度
  3. 层次化方法:先粗粒度匹配整体结构,再细粒度匹配具体内容
# 长文档分块示例 from nltk.tokenize import sent_tokenize def long_doc_similarity(doc1, doc2, model): # 分句 sents1 = sent_tokenize(doc1) sents2 = sent_tokenize(doc2) # 编码所有句子 emb1 = model.encode(sents1) emb2 = model.encode(sents2) # 计算所有句子对之间的相似度 sim_matrix = util.cos_sim(emb1, emb2) # 取最大相似度作为段落间相似度 max_sims = torch.max(sim_matrix, dim=1)[0] return torch.mean(max_sims).item()

5.2 跨语言相似度计算

使用多语言模型如mBERT或XLM-R可以直接计算不同语言文本之间的相似度。

# 加载多语言模型 multi_model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2') chinese_text = "我喜欢编程" english_text = "I enjoy coding" # 计算跨语言相似度 emb1 = multi_model.encode(chinese_text) emb2 = multi_model.encode(english_text) similarity = util.cos_sim(emb1, emb2) print(f"中英文本相似度: {similarity.item():.2f}")

在实际项目中,文本相似度的应用远不止于此。我曾经在一个电商项目中,使用SBERT结合用户行为数据来优化商品推荐系统,将点击率提升了15%。关键在于理解不同算法的特性,并根据具体场景选择合适的方案。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/24 4:34:39

谱分析与可解释性AI揭示:为何BERT等模型难以区分真假信息

1. 项目概述:当机器学习遇上“谎言”检测的困局在信息爆炸的时代,虚假信息如同数字世界的“病毒”,其传播速度和破坏力远超想象。作为一名长期关注自然语言处理(NLP)与机器学习交叉应用的研究者,我常常被问…

作者头像 李华
网站建设 2026/5/24 4:33:48

HP-MOCD:高性能多目标进化社区检测算法解析

1. 高性能多目标进化社区检测算法HP-MOCD解析社区检测作为复杂网络分析的核心技术,其目标是通过识别网络中节点间的密集连接模式来揭示潜在的功能模块。传统基于单目标的社区检测方法(如模块度优化)往往只能捕捉网络结构的单一特征&#xff0…

作者头像 李华
网站建设 2026/5/24 4:33:47

应对数据不平衡:嵌入式运动传感的定制化损失函数与分层模型设计

1. 项目概述:当机器学习遇上嵌入式运动传感 在智能照明、安防监控这些我们日常接触的领域,运动传感器是背后的“隐形守护者”。你可能没注意过它,但它时刻在判断:走廊里是有人走过,还是仅仅是一阵风?办公室…

作者头像 李华
网站建设 2026/5/24 4:30:14

分布式计算演进:从云边协同到无服务器与智能体计算

1. 分布式计算的演进脉络:从集中到泛在在过去的十几年里,我亲眼见证了计算资源从机房里的庞然大物,一步步“溶解”到我们生活的每一个角落。这背后,是分布式计算这条主线在持续演进和裂变。它的核心思想一直没变:把一个…

作者头像 李华
网站建设 2026/5/24 4:26:04

聚合学习:破解大规模MIMO在线信道预测的小样本难题

1. 项目概述:当信道预测遇上在线学习在5G和6G通信系统的核心——大规模多输入多输出(Massive MIMO)技术中,波束成形是实现高容量和广覆盖的基石。然而,这块基石的稳固性,完全依赖于一个看似简单却极其脆弱的…

作者头像 李华