以下是几种基于语义的字符串相似度计算方法,每种方法都会返回0.0到1.0之间的相似度分数(保留一位小数)。
文章目录
方法1:计算 Levenshtein 距离 (基于字符的相似度)
如果需要基于字符的相似度而非语义,可以使用 Levenshtein 距离。
先安装模块:
pip install Levenshtein
案例代码:
import Levenshtein
def levenshtein_similarity(text1, text2):
# 计算 Levenshtein 距离
distance = Levenshtein.distance(text1, text2)
# 计算相似度并保留一位小数
max_len = max(len(text1), len(text2))
similarity = round(1 - (distance / max_len), 1) if max_len > 0 else 1.0
return similarity
# 示例用法
text1 = "kitten"
text2 = "sitting"
print(levenshtein_similarity(text1, text2)) # 输出为 0.5
方法2:使用Sentence-BERT预训练模型
Sentence Transformers 可以将文本转换为语义向量,然后通过余弦相似度计算文本之间的相似度。
使用Sentence-BERT模型计算语义相似度,需要先安装:
pip install sentence-transformers
案例代码:
from sentence_transformers import SentenceTransformer, util
import numpy as np
def semantic_similarity_sbert(str1, str2):
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
# 编码句子
embeddings = model.encode([str1, str2])
# 计算余弦相似度
cosine_score = util.cos_sim(embeddings[0], embeddings[1])
# 转换为0-1范围并保留一位小数
similarity = float(np.clip(cosine_score.item(), 0.0, 1.0))
return round(similarity, 1)
# 示例
print(semantic_similarity_sbert("我喜欢吃苹果", "我爱吃水果")) # 输出类似: 0.8
方法3:使用spaCy进行语义相似度比较
spaCy 是一个强大的自然语言处理库,可以通过预训练模型来计算两个文本的语义相似度。
需要先安装:
pip install spacy
英语模型,需要先安装:
python -m spacy download en_core_web_md
中文模型:
python -m spacy download zh_core_web_lg
案例代码:
import spacy
def spacy_similarity(text1, text2):
# 加载模型
nlp = spacy.load('zh_core_web_lg')
doc1 = nlp(text1)
doc2 = nlp(text2)
# 计算语义相似度并保留一位小数
similarity = round(doc1.similarity(doc2), 1)
return similarity
# 示例用法
text1 = "The cat sits on the mat."
text2 = "A cat is resting on a mat."
print(spacy_similarity(text1, text2)) # 输出可能为 0.8
方法4:使用spaCy和词向量
使用 Word Mover’s Distance (WMD),WMD 是一种基于词向量的距离度量,可以用来计算文本之间的语义差异,通过转换为相似度。
import spacy
import numpy as np
def semantic_similarity_spacy(str1, str2):
"""
使用spaCy的词向量计算语义相似度
"""
nlp = spacy.load("zh_core_web_lg")
doc1 = nlp(str1)
doc2 = nlp(str2)
# 计算余弦相似度
similarity = doc1.similarity(doc2)
# 确保在0-1范围内并保留一位小数
return round(max(0.0, min(1.0, similarity)), 1)
# 示例
print(semantic_similarity_spacy("今天天气很好", "明天的天气不错")) # 输出类似: 0.7
方法5:使用Universal Sentence Encoder (USE)
使用Google的Universal Sentence Encoder需要先安装:
pip install tensorflow-hub tensorflow-text
注意: 首次使用需要下载模型(约900MB)
import tensorflow_hub as hub
import tensorflow_text as text # 必须导入
import numpy as np
def semantic_similarity_use(str1, str2):
"""
"""
module = hub.load("https://tfhub.dev/google/universal-sentence-encoder-multilingual/3")
# 编码句子
embeddings = module([str1, str2])
# 计算余弦相似度
similarity = np.inner(embeddings[0], embeddings[1]) / (
np.linalg.norm(embeddings[0]) * np.linalg.norm(embeddings[1])
)
# 确保在0-1范围内并保留一位小数
return round(max(0.0, min(1.0, similarity)), 1)
# 示例
print(semantic_similarity_use("这只猫很可爱", "那只猫咪非常漂亮")) # 输出类似: 0.8
方法6:使用BERT-as-Service
使用BERT-as-Service计算语义相似度
需要先安装:
pip install bert-serving-server bert-serving-client
并下载预训练模型运行服务端
from bert_serving.client import BertClient
import numpy as np
def semantic_similarity_bert(str1, str2):
"""
"""
bc = BertClient()
# 编码句子
embeddings = bc.encode([str1, str2])
# 计算余弦相似度
similarity = np.dot(embeddings[0], embeddings[1]) / (
np.linalg.norm(embeddings[0]) * np.linalg.norm(embeddings[1])
)
# 确保在0-1范围内并保留一位小数
return round(max(0.0, min(1.0, similarity)), 1)
# 示例
# print(semantic_similarity_bert("他正在跑步", "他在运动")) # 输出类似: 0.9
方法7:使用TF-IDF和余弦相似度(基于词频统计)
这是一种基于词频的相似度计算方法。
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
def semantic_similarity_tfidf(str1, str2):
"""
使用TF-IDF和余弦相似度计算文本相似度
基于词频统计,不是真正的语义相似度,但可以作为基线方法
"""
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform([str1, str2])
# 计算余弦相似度
similarity = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2])[0][0]
# 确保在0-1范围内并保留一位小数
return round(max(0.0, min(1.0, similarity)), 1)
# 示例
print(semantic_similarity_tfidf("深度学习", "神经网络")) # 输出类似: 0.6
方法8:博主自创算法
结巴分词、TF-IDF的余弦相似度、标准化编辑距离相似度:
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import Levenshtein
class SemanticSimilarity:
def __init__(self):
self.vectorizer = TfidfVectorizer()
def tokenize(self, text):
"""中文分词处理"""
return ' '.join(jieba.lcut(text))
def tfidf_cosine(self, str1, str2):
"""基于TF-IDF的余弦相似度(0-1)"""
corpus = [self.tokenize(str1), self.tokenize(str2)]
tfidf = self.vectorizer.fit_transform(corpus)
return max(0.0, min(1.0, cosine_similarity(tfidf[0], tfidf[1])[0][0]))
def edit_similarity(self, str1, str2):
"""标准化编辑距离相似度(0-1)"""
distance = Levenshtein.distance(str1, str2)
max_len = max(len(str1), len(str2))
return max(0.0, min(1.0, 1 - (distance / max_len))) if max_len > 0 else 1.0
def combined_similarity(self, str1, str2):
"""综合语义相似度(保留1位小数)"""
tfidf_score = self.tfidf_cosine(str1, str2)
edit_score = self.edit_similarity(str1, str2)
return round(0.6 * tfidf_score + 0.4 * edit_score, 1)
if __name__ == '__main__':
ss = SemanticSimilarity()
str1 = "第十八条 【商标代理】外国人或者外国企业在中国申请商标注册和办理其他商标事宜的,应当委托国家认可的具有商标代理资格的组织代理。"
str2 = "第十八条 申请商标注册或者办理其他商标事宜,可以自行办理,也可以委托依法设立的商标代理机构办理。"
print(f"相似度: {ss.combined_similarity(str1, str2)}")
综合比较
- Levenshtein:基于字符的相似度而非语义,简单快速,但不是真正的语义相似度
- Sentence-BERT:轻量级,效果好,支持多语言,推荐使用
- spaCy:中等大小,适合英文,中文需要大模型
- TF-IDF:简单快速,但不是真正的语义相似度
- USE:Google官方模型,效果好但模型较大
- BERT-as-Service:需要额外服务,适合生产环境
- 博主自创算法:结合了结巴分词、TF-IDF的余弦相似度、标准化编辑距离,效果好,运行速度块,并且还可以自行修改占比。
注意事项
- 中文处理需要确保使用支持中文的模型
- 语义相似度计算通常需要较多的计算资源
- 对于生产环境,建议使用Sentence-BERT或USE
- 首次使用某些方法需要下载大型预训练模型
选择哪种方法取决于你的具体需求、计算资源和语言要求。