常见文本相似度计算法
0 引言
在自然语言处理任务中,我们经常需要判断两篇文档是否相似、计算两篇文档的相似程度。比如,基于聚类算法发现微博热点话题时,我们需要度量各篇文本的内容相似度,然后让内容足够相似的微博聚成一个簇;在问答系统中,我们会准备一些经典问题和对应的答案,当用户的问题和经典问题很相似时,系统直接返回准备好的答案;在监控新闻稿件在互联网中的传播情况时,我们可以把所有和原创稿件相似的文章,都看作转发,进而刻画原创稿件的传播范围;在对语料进行预处理时,我们需要基于文本的相似度,把重复的文本给挑出来并删掉……总之,文本相似度是一种非常有用的工具,可以帮助我们解决很多问题。
1 文本相似度计算任务的简单分析
文本的相似性计算,是我们常说的“文本匹配任务”的一种特殊情况。
1.1 任务目标
一般来说,文本相似度计算任务的输入,是两篇文档,比如表1-1的前两个句子;输出是两篇文档的相似程度,通常用[0,1]区间内的小数来表示。作为一个懂人话的人类,我知道句子1和句子2的内容是一样的,并认为计算二者的相似性非常简单。
假如说,我们要判断1万对文档的相似性,或者在1秒内判断100对文档的相似度呢?那我就不行了,需要上机器。
大家在生活里和可能已经用到了文本相似度计算支持的东西。很多产品(APP,网站,导游机器人等等)配备了问答系统,允许用户用自然语言向系统发出各种请求。系统会理解用户的语言,然后返回一定形式的内容并展示在终端展里,作为对用户的回答。有些问题比较经典,大家经常问到。工程师或者领域专家会把这些问题和对应的答案收集并存储起来——当用户再次问到类似的问题时,直接返回现成的答案即可。“类似”与否的判断,需要使用文本相似度计算来支持。
那么,如何让机器替我们完成文本相似度的计算呢?
表1-1 我对机器人说的话
序号 |
问句 |
问题答案pairs |
|
问句 |
答案 |
||
1 |
我想去厕所 |
厕所位置是哪里? |
左手边直走30米。请看我的地图… |
2 |
撒尿哪里走? |
||
3 |
请问卫生间在哪里? |
||
4 |
请问厕所在哪里? |
||
5 |
饿死了,有啥建议啊? |
附近的餐厅在哪里? |
左手边直走31米。请看地图… |
1.2 候选方案
文本相似度计算方法有2个关键组件,即文本表示模型和相似度度量方法,如表1-2。前者负责将文本表示为计算机可以计算的数值向量,也就是提供特征;后者负责基于前面得到的数值向量计算文本之间的相似度。
从文本表示模型和相似度度量方法中选择合适的,就可以组合出一个文本相似度计算方案。
表1-2 常见的文本表示模型和相似度度量方法
文本表示模型 |
相似度度量方法 |
|
文本切分粒度 |
特征构建方法 |
|
原始字符串 ngram 词语 句法分析结果 主题模型
|
TF TF-IDF 句向量 词向量 Simhash
|
最小编辑距离 欧氏距离 余弦距离 杰卡德相似度 |
海明距离 |
||
分类器 |
使用这个菜单里的选项,我们可以组合出非常多的文本相似度计算方案。那么,每一种方案都可以用来解决什么样的任务呢?要回答这个问题,需要了解一下每一个组件的原理和特点。
2 有监督和无监督的文本相似性计算
文本相似度计算方法分为有监督和无监督两类。
有监督方法,就是用朴素贝叶斯分类器之类的有监督模型来判断文本相似性或者计算相似度。这类方法要求有一定数量的标注语料,构建的代价比较高;由于训练语料通常无法做得很大,模型的泛化性不够,实际用起来会有点麻烦;距离计算环节的复杂度会比较高。
无监督方法,就是用欧氏距离等方法,直接计算文本之间的距离或者相似度。这类方法的特点是:不需要标注语料,特征工程或者参数估计可以使用很大的数据;很多方法对语言的依赖比较小,可以应对多语种混杂的场景;距离计算环节复杂度较低。
通常来说我们首先考虑无监督模式。
3 文本切分粒度
3.1 n-gram
我们常说的“n-gram语言模型“,指的是一类使用相同文本切分方式的语言模型。这种切分方式非常简单:使用一个长度为n的窗口,从左到右、逐字符滑过文本;每一步,会框到一个字符串,就是一个gram;文本里所有的gram就是该文本的切分结果。如表3-1所示,是几种常见的n-gram切分结果。
表3-1 “我爱北京天安门”的n-gram表示
序号 |
N取值 |
名称 |
切分示例 |
1 |
1 |
unigram |
我/爱/北/京/天/安/门 |
2 |
2 |
bigram |
我爱/爱北/北京/京天/天安/安门 |
3 |
3 |
trigram |
我爱北/爱北京/北京天/京天安/天安门 |
… |
… |
… |
… |
n-gram越长,词表越大。一份中文语料的Trigram词表可以达到上百万的规模。要是来个quadgram,由于内存消耗较大、特征很稀疏,我们的工作会很难开展。
3.2 分词
另外一种文本切分方式就是分词,比如将“我爱北京天安门”切分为“我/爱/北京/天安门”。分词的目的是将文本切分为有句法意义的一个个小单元,便于人和机器理解文本的内容。
在NLP进入深度学习时代之前,分词是中文信息处理的基础任务。语言这种序列数据,具有很强的时间/空间相关性。在一段文本序列的某些位置,会出现相关性特别高的若干连续字符,比如“我爱北京天安门”里的“天安门”,这3个字符内部之间的相关性明显高于它们同其他字符的相关性。
相比n-gram,分词的优势是,在字符相关性较小的位置进行切分、造成的信息损失比较小。由于分词降低了文本的相关性,可以提升一些带有独立性假设的模型。
当然,ngram由于极高的计算速度,仍然占有一定的市场。
3.3 句法分析
我们可以基于句法分析的结果,从文本中抽取短语,作为文本的表示。这样得到的特征非常稀疏,适合精度要求较高的场景。
3.3.1 粗暴版句法分析
我们可以用一些规则或者模型,从文本中提取特定的词语组合,作为文本的切分结果。比如用“第一个名词+第一个动词+第二个名词”这个规则处理“我爱北京天安门”的结果是“我+爱+北京”。
3.3.2 正经句法分析
可以使用正经的句法分析工具,提取“主+谓+宾”之类的,作为文本的切分结果。句法分析的耗时比较高,适合数据量小的场景。
3.4 主题模型
可以使用主题模型来提取文本的主题,用主题词来表示文本。常见的主题模型有PLSA、LDA以及它们的变种(LSA适用于教学场景;还有很多优秀的主题模型,所知甚少,不多介绍)。主题模型在训练的过程中,学习到了语料的全局信息,因此具有一定的“联想”或者说“推理”能力,可以基于文档内容推测出文档字面没有明说的一些信息。因此,主题模型可以处理一些需要关注隐藏信息的场景。
当然了,主题模型的训练比较慢、对语料规模和质量有较高的要求,因此考虑是否使用的时候需要慎重。
4 特征构建方法
文本相似度计算任务的第二步,是用数值向量表示文本的内容。通常,我们会用一个数值向量描述文本在语义空间中的位置。
4.1 TF与TF-IDF
词袋模型(bag of words)假设,文本里的term(虽然名字里是”words”,实际上我们也可以用n-gram之类的切分方式)之间相互独立,也就是词语A的出现和词语B的出现没有关系。
我们可以用独热编码表示所有的term,然后对文本中的term去重,最后把得到的term的编码加起来,就得到了TF向量。
TF向量对常用词比较友好。假设有一份红学文集构成的语料,里面“红楼梦”“贾宝玉”这样的词语几乎会出现在每一篇文档里,相应的频率还很高。结果就是这样的词语“统治”了TF向量,导致两篇文档比较相似。换句话说,TF对文档的区分能力比较低。
4.2 词向量和句向量
4.3 simhash
4.3.1 simhash简介
Simhash是敏感哈希算法在文本特征提取任务中的应用。它会把一篇文档映射为一个长度为64、元素值为0或1的一维向量。这样我们就可以使用某种距离计算方式,计算两篇文本的距离和相似度了。一般来说,与simhash配合的是海明距离。
4.3.2 simhash的适用场景
Simhash的特点是,对文本的“相同”与否特别敏感:当两篇文档相同时,相似度为1;当其中一篇略有不同,相似度会有明显降低。因此非常适合用来判断两篇文档内容是否相同。
另外simhash的计算比较简单,速度上有一定优势。如果配合一定的检索策略来召回候选相似文档,simhash可以用来对海量文档进行去重——这就是simhash最常见的一个应用场景。
5 距离的度量方式
假设表1-1的3句和4句分词结果分别为:
5.1 欧氏距离
5.1.1 欧氏距离的计算方法
假设我们有两个数值向量,表示两个实例在欧式空间中的位置:
二者的欧氏距离是这样计算的:
如图5-1,二维空间(平面)里有两个点 和 。二者在X轴上的差异大小是 ,在Y轴上的差异是 。综合两个坐标轴上的差异,就得到了两点之间的距离: 。
欧式距离是最符合我们直觉的一种距离度量方式。它认为事物的所有特征都是平等的。两个实例在所有维度上的差异的总和,就是二者的距离。
5.1.2 应用场景
编码检测等类似领域。两串编码必须完全一致,才能通过检测,这时一个移位或者一个错字,可能会造成非常严重的后果。比如下图第一个二维码是 “这是一篇文本相似度的文章”,第二个是 “这是一篇文本相似度文章”。从人的理解来看,这两句话相似度非常高,但是生成的二维码却千差万别。
(2)不适用场景
文本相似度,意味着要能区分相似 / 差异的程度,而欧氏距离更多的只能区分出是否完全一样。而且,欧氏距离对位置、顺序非常敏感,比如 “我的名字是孙行者” 和“孙行者是我的名字”,在人看来,相似度非常高,但是用欧氏距离计算,两个文本向量每个位置的值都不同,即完全不匹配。
5.2 曼哈顿距离
适用场景同欧氏距离。
5.3 编辑距离(Levenshtein 距离、莱文斯坦距离)
顾名思义,编辑距离指的是将文本 A 编辑成文本 B 需要的最少变动次数(每次只能增加、删除或修改一个字)。编辑距离是对称的,即将 A 转化成 B 的最小变动次数和将 B 转化成 A 的最小变动次数是相等的。
同时,编辑距离与文本的顺序有关。
应用场景
(1)适用场景
编辑距离算出来很小,文本相似度肯定很高。如果用算法语言来说的话,就是准确率很高(即虽然会漏掉一些好的case,但可以确保选出来的case 一定非常好)。
(2)不适用场景
反过来说,虽然准确率很高,但召回率不高。在某些业务场景中,漏掉的 case 会引起严重后果,比如 “批发零售” 和“零售批发”,人的理解应该非常相似,可编辑距离却是 4,相当于完全不匹配,这显然不符合预期。
5.4 余弦相似度
5.4.1 余弦距离的计算方式
余弦相似度的灵感来自于数学中的余弦定理,这里对数学内容不做过多解释,直接上公式:
其中,A、B 分别是文本一、文本二对应的 n 维向量。
举例:
文本A是 “一个雨伞”,文本B是 “下雨了开雨伞”,它们的并集是 {一,个,雨,伞,下,了,开},共 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 代入计算公式,得到
5.4.2 应用场景
(1)适用场景
余弦相似度和杰卡德相似度虽然计算方式差异较大,但性质上很类似(与文本的交集高度相关),所以适用场景也非常类似。余弦相似度相比杰卡德相似度最大的不同在于它考虑到了文本的频次,比如上面例子出现了 2 次 “雨”,和只出现 1 次“雨”,相似度是不同的;再比如“这是是是是是是一个文本” 和“这是一个文文文文文文本”,余弦相似度是 39%,整体上符合 “相同的内容少于一半,但超过 1/3” 的观感(仅从文本来看,不考虑语义)。
(2)不适用场景
向量之间方向相同,但大小不同的情况(这种情况下余弦相似度是 100%)。比如 “太棒了” 和“太棒了太棒了太棒了”,向量分别是(1,1,1)和(3,3,3),计算出的相似度是 100%。这时候要根据业务场景进行取舍,有些场景下我们认为它们意思差不多,只是语气程度不一样,这时候余弦相似度是很给力的;有些场景下我们认为它们差异很大,哪怕意思差不多,但从文本的角度来看相似度并不高(最直白的,一个 3 个字,一个 9 个字),这时候余弦相似度就爱莫能助了。
5.5 Jacard相似度
5.5.1 杰卡德相似度的计算方式
杰卡德相似度一般被用来度量两个集合之间的差异大小。假设我们有两个集合A和B,那么二者的杰卡德相似度为:
杰卡德距离的思想非常简单:两个集合共有的元素越多,二者越相似;为了控制距离的取值范围,我们可以增加一个分母,也就是两个集合拥有的所有元素。杰卡德相似度与文本的位置、顺序均无关。比如 “王者荣耀” 和“荣耀王者”的相似度是 100%。无论 “王者荣耀” 这 4 个字怎么排列,最终相似度都是 100%。在某些情况下,会先将文本分词,再以词为单位计算相似度。比如将 “王者荣耀” 切分成 “王者 / 荣耀”,将“荣耀王者” 切分成“荣耀 / 王者”,那么交集就是{王者,荣耀},并集也是{王者,荣耀},相似度恰好仍是 100%。
5.5.2 应用场景
(1)适用场景
对字 / 词的顺序不敏感的文本,比如前述的 “零售批发” 和“批发零售”,可以很好地兼容。长文本,比如一篇论文,甚至一本书。如果两篇论文相似度较高,说明交集比较大,很多用词是重复的,存在抄袭嫌疑。
(2)不适用场景
重复字符较多的文本,比如 “这是是是是是是一个文本” 和“这是一个文文文文文文本”,这两个文本有很多字不一样,直观感受相似度不会太高,但计算出来的相似度却是 100%(交集 = 并集)。对文字顺序很敏感的场景,比如 “一九三八年” 和“一八三九年”,杰卡德相似度是 100%,意思却完全不同。
5.6 海明距离
海明距离是simhash算法的御用距离算法。
5.6.1 海明距离的计算方式
海明距离的计算方式非常简单。如5.1.1所述,两个句子可以用词袋模型来表示:
我们比较两篇文档的特征向量的每一个维度,判断各个维度上取值是否相等。不相等的维度越多,两篇文档差异越大。海明距离的计算方式如下:
其中,
5.6.2 基于海明距离的文本相似度
换个角度,两篇文档的特征向量里,相等的维度越多,相似度就越大。相似度的计算方法如下:
其中,
5.7 最小编辑距离
最小编辑距离是一种经典的距离计算方法,用来度量字符串之间的差异。它认为,将字符串A不断修改(增删改)、直至成为字符串B,所需要的修改次数代表了字符串A和B的差异大小。当然了,将A修改为B的方案非常多,选哪一种呢?我们可以用动态规划找到修改次数最小的方案,然后用对应的次数来表示A和B的距离。
从定义上可以看出,最小编辑距离比较适合判断字面上的相似性,对文本字语义上的相似性无能为力。
6 结语
相似度计算不光在文本数据处理里经常用到,在图像、音频、生物信息等等类型数据的处理中也有很高的出场率。对应地,相似度计算可以帮助我们解决生产活动里的很多具体问题。因此,它是一种非常有用的方法,值得我们仔细琢磨。
判断事物之间的相似性,是我们需要和喜欢的一种活动。我们在生活中,无时不刻在进行着一种活动:判断接触到的事物是否从未见过;如果没见过,就会思考哪些已知的东西和它类似;如果它太独特、可借鉴的经验很少,就认为它是一种新的事物;如果有很多类似的已知事物,我们会基于经验对它分析一波,并在这个基础上快速地加以了解。
参考: