NLP自然语言处理中的文本相似度

1. 背景介绍

CSDN 及各类技术博客上有很多文本相似度方面的文章,但它们的侧重点是代码,目标受众是开发人员,代码基础薄弱的话看起来会比较吃力。

本文侧重讲述逻辑和使用场景,尝试将算法通俗化,尽量多举例,降低理解门槛。希望读完本文,大家可以对文本相似度有一个完整而深刻的理解,最好能在非代码维度上超过开发人员(达到了这种水平,输出的需求自然会得到开发同学最大的尊重和认同)。

文本相似度,顾名思义是指两个文本(文章)之间的相似度,在搜索引擎、推荐系统、论文鉴定、机器翻译、自动应答、命名实体识别、拼写纠错等领域有广泛的应用。

总的来说,文本相似度是自然语言处理(NLP)中必不可少的重要环节,几乎所有 NLP 的领域都会涉及到!

与之相对应的,还有一个概念——文本距离——指的是两个文本之间的距离。文本距离和文本相似度是负相关的——距离小,“离得近”,相似度高;距离大,“离得远”,相似度低。业务上不会对这两个概念进行严格区分,有时用文本距离,有时则会用文本相似度。

 

2. 各类算法

2.1 欧氏距离

数学中的一个非常经典的距离,公式如下:

NLP自然语言处理中的文本相似度_第1张图片

例 1:计算 “产品经理” 和“产业经理是什么”之间的欧氏距离

过程如下:

  • 文本向量 A=(产,品,经,理),即 x1 = 产,x2 = 品,x3 = 经,x4 = 理,x5、x6、x7 均为空;
  • 文本向量 B=(产,业,经,理,是,什,么),即 y1 = 产,y2 = 业,y3 = 经,y4 = 理,y5 = 是,y6 = 什,y7 = 么。

这里规定,若 xi=yi,则 xi-yi=0;若 xi≠yi,|xi-yi|=1。

所以,欧氏距离d是 2

(1)适用场景

编码检测等类似领域。两串编码必须完全一致,才能通过检测,这时一个移位或者一个错字,可能会造成非常严重的后果。比如下图第一个二维码是 “这是一篇文本相似度的文章”,第二个是 “这是一篇文本相似度文章”。从人的理解来看,这两句话相似度非常高,但是生成的二维码却千差万别。

(2)不适用场景

文本相似度,意味着要能区分相似 / 差异的程度,而欧氏距离更多的只能区分出是否完全一样。而且,欧氏距离对位置、顺序非常敏感,比如 “我的名字是孙行者” 和“孙行者是我的名字”,在人看来,相似度非常高,但是用欧氏距离计算,两个文本向量每个位置的值都不同,即完全不匹配。

 

2.2 曼哈顿距离

和欧氏距离非常相似(把平方换成了绝对值,拿掉了根号),公式如下:

适用场景同欧氏距离。

 

2.3 编辑距离(Levenshtein 距离、莱文斯坦距离)

编辑距离(Edit Distance) 一文读懂:https://blog.csdn.net/sinat_26811377/article/details/102652547

 

顾名思义,编辑距离指的是将文本 A 编辑成文本 B 需要的最少变动次数(每次只能增加、删除或修改一个字)。

例 2:计算 “椰子” 和“椰子树”之间的编辑距离。

因为将 “椰子” 转化成 “椰子树”,至少需要且只需要 1 次改动(反过来,将“椰子树” 转化成“椰子”,也至少需要 1 次改动,如下图),所以它们的编辑距离是 1。

NLP自然语言处理中的文本相似度_第2张图片

因此,编辑距离是对称的,即将 A 转化成 B 的最小变动次数和将 B 转化成 A 的最小变动次数是相等的。

同时,编辑距离与文本的顺序有关。

比如,“椰子”和 “子椰”,虽然都是由“椰”“子” 组成,但因为顺序变了,编辑距离是 2(如下图),而不是 0。

NLP自然语言处理中的文本相似度_第3张图片

(1)适用场景

编辑距离算出来很小,文本相似度肯定很高。如果用算法语言来说的话,就是准确率很高(即虽然会漏掉一些好的 case,但可以确保选出来的 case 一定非常好)。

(2)不适用场景

反过来说,虽然准确率很高,但召回率不高。在某些业务场景中,漏掉的 case 会引起严重后果,比如 “批发零售” 和“零售批发”,人的理解应该非常相似,可编辑距离却是 4,相当于完全不匹配,这显然不符合预期。

 

2.4 Jaccard 相似度(杰卡德相似度)

杰卡德相似度,指的是文本 A 与文本 B 中交集的字数除以并集的字数,公式非常简单:

如果要计算 Jaccard 距离,公式稍作变更即可:

例 3:计算 “荒野求生” 和“绝地求生”的杰卡德相似度。

因为它们交集是 {求,生},并集是 {荒,野,求,生,绝,地},所以它们的杰卡德相似度 = 2/6=1/3。

杰卡德相似度与文本的位置、顺序均无关。比如 “王者荣耀” 和“荣耀王者”的相似度是 100%。无论 “王者荣耀” 这 4 个字怎么排列,最终相似度都是 100%。

在某些情况下,会先将文本分词,再以词为单位计算相似度。比如将 “王者荣耀” 切分成 “王者 / 荣耀”,将“荣耀王者” 切分成“荣耀 / 王者”,那么交集就是{王者,荣耀},并集也是{王者,荣耀},相似度恰好仍是 100%。

(1)适用场景

  • 对字 / 词的顺序不敏感的文本,比如前述的 “零售批发” 和“批发零售”,可以很好地兼容。
  • 长文本,比如一篇论文,甚至一本书。如果两篇论文相似度较高,说明交集比较大,很多用词是重复的,存在抄袭嫌疑。

(2)不适用场景

  • 重复字符较多的文本,比如 “这是是是是是是一个文本” 和“这是一个文文文文文文本”,这两个文本有很多字不一样,直观感受相似度不会太高,但计算出来的相似度却是 100%(交集 = 并集)。
  • 对文字顺序很敏感的场景,比如 “一九三八年” 和“一八三九年”,杰卡德相似度是 100%,意思却完全不同。

 

2.5 余弦相似度

余弦相似度的灵感来自于数学中的余弦定理,这里对数学内容不做过多解释,直接上公式:

NLP自然语言处理中的文本相似度_第4张图片

其中,A、B 分别是文本一、文本二对应的 n 维向量。取值方式用语言比较难描述,直接看例子吧:

 

例 4:文本一是 “一个雨伞”,文本二是 “下雨了开雨伞”,计算它们的余弦相似度。

它们的并集是 {一,个,雨,伞,下,了,开},共 7 个字。

  • 若并集中的第 1 个字符在文本一中出现了 n 次,则 A1=n(n=0,1,2……)。
  • 若并集中的第 2 个字符在文本一中出现了 n 次,则 A2=n(n=0,1,2……)。

依此类推,算出 A3、A4、……、A7,B1、B2、……、B7,最终得到:

  • A=(1,1,1,1,0,0,0)。
  • B=(0,0,2,1,1,1,1)。

将 A、B 代入计算公式,得到

(1)适用场景

余弦相似度和杰卡德相似度虽然计算方式差异较大,但性质上很类似(与文本的交集高度相关),所以适用场景也非常类似。

余弦相似度相比杰卡德相似度最大的不同在于它考虑到了文本的频次,比如上面例子出现了 2 次 “雨”,和只出现 1 次“雨”,相似度是不同的;再比如“这是是是是是是一个文本” 和“这是一个文文文文文文本”,余弦相似度是 39%,整体上符合 “相同的内容少于一半,但超过 1/3” 的观感(仅从文本来看,不考虑语义)。

(2)不适用场景

向量之间方向相同,但大小不同的情况(这种情况下余弦相似度是 100%)。

比如 “太棒了” 和“太棒了太棒了太棒了”,向量分别是(1,1,1)和(3,3,3),计算出的相似度是 100%。

这时候要根据业务场景进行取舍,有些场景下我们认为它们意思差不多,只是语气程度不一样,这时候余弦相似度是很给力的;有些场景下我们认为它们差异很大,哪怕意思差不多,但从文本的角度来看相似度并不高(最直白的,一个 3 个字,一个 9 个字),这时候余弦相似度就爱莫能助了。

 

2.6 Jaro 相似度

Jaro 相似度据说是用来判定健康记录上两个名字是否相同,公式如下:

其中,m 是两个字符串中相互匹配的字符数量;|s1 | 和 | s2 | 表示两个字符串的长度(字符数量);t 是换位数量

这里着重说一下 “匹配” 和 “换位” 的概念,先列一个公式,我称之为 “匹配阈值”:

当 s1 中某字符与 s2 中某字符相同,且它们的位置相距小于等于 k 时,就说它们是匹配的。

比如 “我明白了” 和“快一点告诉我”,按公式算出 k=2。虽然两个字符串中都有 “我” 字,但一个在第 1 位,另一个在第 6 位,相距为 5,大于 k 值,所以这两个字符串没有任何一个字符是匹配的。

再比如 “我明白了” 和“明白了我”,k=1,所以这两个字符串的 “明”“白”“了” 是匹配的,但是 “我” 是不匹配的,所以它们有 3 个字符是匹配的。

换位的意思,是将 s1 和 s2 匹配的字符依次抽出来,看它们顺序不一样的字符有多少个,这个数就是换位数量。

例 5:计算 “我表白了一个女孩” 和“近几天我白表了一次情”的 Jaro 相似度。

|s1|=8,|s2|=10,k=4,匹配的字符有 5 个,即 m=5,分别是 “我”“表”“白”“了”“一”。

将 s1 中的匹配字符依次抽出来,得到一个向量 r1=(我,表,白,了,一)。

将 s2 中的匹配字符依次抽出来,得到一个向量 r2=(我,白,表,了,一)。

比对 r1 和 r2,发现有 2 个位置的值不一样(第 2 位和第 3 位),所以换位数 t=2。

于是,d=1/3[5/8+5/10+(5-2)/5]=57.5%。

(1)适用场景

对位置、顺序敏感的文本。文本位置的偏移,很容易使匹配字符数 m 变少;文本顺序的变换,会使换位数量 t 增大。它们都会使 Jaro 相似度减小。换句话说,如果某业务场景下需要考虑文本位置偏移、顺序变换的影响,既不希望位置或顺序变了相似度却保持不变,又不希望直接一刀切将相似度变为 0,那 Jaro 距离是十分合适的。

(2)不适用场景

未知(什么!作者这么任性的吗?)。

其实,我自己确实没想清楚,也没有在实践中使用过这个算法。

整体来说,Jaro 距离是比较综合的文本相似度算法,从换位字符数来看,有点像编辑距离;从匹配字符的抽取来看,又有点像 “交集”。

最后,对例 5 做个横向对比:“我表白了一个女孩” 和“近几天我白表了一次情”

  • 方法3的编辑距离算出来是 8,s1 长度是 8,s2 长度是 10,编辑距离等于 8,从数据上看非常不相似,与人的感官差异很大。
  • 方法4的杰卡德相似度算出来是 38.5%,数值比较低,和人的感官差异较大。
  • 方法5的余弦相似度算出来是 55.9%,和 Jaro 距离算出来差不多,都是 50%+,比较符合人的感官——超过一半的内容是相同的,同时有将近一半内容是不同的。
  • 如果在此例中,调整字符顺序,让换位数量 t 变大,匹配数量 m 变小,余弦相似度不变,Jaro 相似度会降低。

 

3. 拓展阅读

3.1 名词解释

算法中的重要概念(指标)——准确率、精确率、召回率。其中准确率和精确率很容易混淆,详细差别可以点开以下链接:http://t.cn/R6y8ay9

3.2 贝叶斯公式

NLP 领域,我个人认为有两个非常重要的、频繁出现的基本公式,一个是前述的文本相似度,另一个就是贝叶斯公式了。对这块有兴趣的同学,可以阅读下文:http://t.cn/haY0x

作者写的非常易于理解——我在《深度学习》这本书里看 NLP 相关内容时,有几个公式怎么都理解不了,看这篇文章简直是秒懂。

3.3 代码

编辑距离的代码见百度百科最底部,有兴趣的同学可以扩展阅读:http://t.cn/R850kBe

余弦相似度的代码见这篇 CSDN 博客 ,写的比较详细:http://t.cn/R850ru8

切记,一定要在电脑上打开链接查看代码(别问我怎么知道的)。

PS. 代码这一块我就意思一下,不是重点,不再每个算法都一一列举了。

你可能感兴趣的:(自然语言处理,NLP)