在做自然语言处理的过程中,我们经常会遇到需要找出相似语句的场景,或者找出句子的近似表达,这时候就需要把类似的句子归到一起,这里面就涉及到句子相似度计算的问题。
基本方法
句子相似度计算一共归类了以下几种方法:
- 编辑距离计算
- 杰卡德系数计算
- TF 计算
- TF-IDF 计算
- Word2Vec 计算
下面来一一了解一下这几种算法的原理和 Python 实现。
编辑距离计算
编辑距离,英文叫做 Edit Distance,又称 Levenshtein 距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数,如果它们的距离越大,说明它们越是不同。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
例如我们有两个字符串:string 和 setting,如果我们想要把 string 转化为 setting,需要这么两步:
- 第一步,在 s 和 t 之间加入字符 e。
- 第二步,把 r 替换成 t。
所以它们的编辑距离差就是 2,这就对应着二者要进行转化所要改变(添加、替换、删除)的最小步数。
那么用 Python 怎样来实现呢,我们可以直接使用 distance 库:
#编辑距离
import distance
def edit_distance(s1, s2):
return distance.levenshtein(s1, s2)
strings = [
'你在干什么',
'你在干啥子',
'你在做什么',
'你好啊',
'我喜欢吃香蕉'
]
target = '你在干啥'
results = list(filter(lambda x: edit_distance(x, target) <= 2, strings))
print(results)
'''
['你在干什么', '你在干啥子']
'''
通过这种方式我们可以大致筛选出类似的句子,但是发现一些句子例如“你在做什么” 就没有被识别出来,但他们的意义确实是相差不大的,因此,编辑距离并不是一个好的方式,但是简单易用。
杰卡德系数计算
杰卡德系数,英文叫做 Jaccard index, 又称为 Jaccard 相似系数,用于比较有限样本集之间的相似性与差异性。Jaccard 系数值越大,样本相似度越高。
实际上它的计算方式非常简单,就是两个样本的交集除以并集得到的数值,当两个样本完全一致时,结果为 1,当两个样本完全不同时,结果为 0。
算法非常简单,就是交集除以并集,下面我们用 Python 代码来实现一下:
#杰卡德系数计算
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
def jaccard_similarity(s1, s2):
def add_space(s):
return ' '.join(list(s))
# 将字中间加入空格
s1, s2 = add_space(s1), add_space(s2)
# 转化为TF矩阵
cv = CountVectorizer(tokenizer=lambda s: s.split())
corpus = [s1, s2]
vectors = cv.fit_transform(corpus).toarray()
# 求交集
numerator = np.sum(np.min(vectors, axis=0))
# 求并集
denominator = np.sum(np.max(vectors, axis=0))
# 计算杰卡德系数
return 1.0 * numerator / denominator
s1 = '你在干嘛呢'
s2 = '你在干什么呢'
print(jaccard_similarity(s1, s2))
'''
0.5714285714285714
'''