自然语言处理 | (30) 文本相似度计算与文本匹配问题

本文围绕文本相似度问题展开,介绍了其在搜索系统、问答系统等方面的应用。详细阐述了多种文本相似度模型,如Hamming distance、编辑距离、Jaccard Similarity等。还给出了基于Python实现编辑距离、simhash判断相似文本以及词向量Word AVG的实战内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 目录

 

1. 文本相似度问题与应用

2. 文本相似度模型介绍

3. 实战:基于Python实现编辑距离

4. 实战:基于simhash实现相似文本判断

5. 实战:词向量Word AVG


1. 文本相似度问题与应用

  • 文本相似度问题

文本相似度问题包含:词与词、句与句、段落与段落、篇章与篇章之间的相似度问题;以及词与句、句与段落、段落与篇章等之类的相似度问题,这里的相似指的是语义的相似。这些问题的难度递增。

  • 文本相似度应用

搜索系统:

1)利用query来搜索最相关的文本/网页。

2)利用网页的标题、内容等信息。

问答系统:

用户提问的问题与语料库中的问题进行相似度匹配,选择相似度最高的问题的答案作为回答。

聊天机器人 --- 检索式模型:

利用文本相似度实现问答的聊天机器人例子:

 单看每一轮对话,效果似乎还不错。如果综合多轮对话来看,有些机械,达不到期望的结果。

2. 文本相似度模型介绍

  • Hamming distance

两个相同长度的字符串,有多少个位置是不同的token。 如:d(cap,cat) = 1

距离越小,说明二者越相似;反之,说明差距很大。很显然,这种方法,过于简单,有一些词的词义接近,但完全是不同的两个词,如diffcult,hard等。当然这种方法可能在某种特定的情况下,会有一些作用。

文本相似度强调的是词义、语义的相似,而不是形似。

  • 编辑距离

给定两段文本或两个句子,最少需要经过多少步操作能够从一个句子转化为另一个句子。允许的操作有:

利用动态规划解决编辑距离:

 假设我们比较kitten和sitting这两个单词的相似度(此时操作的基本单位是字符,如果是句子/段落相似度问题的话,基本操作单位就是单词)。

利用动态规划的思想,计算两个字符串的编辑距离,就相当于计算他们子串的编辑距离,再加上从子串到全串需要的最少操作数即可,不断的进行递推。

递推公式如下:

相当于产生了下面的这个编辑距离矩阵:

1)kitten和sitting都是从第一个位置开始,lev_{a,b}(0,0)=0

2) 如果i或j=0,即第0行或第0列,lev_{a,b}(i,j)=max(i,j)

3)当i,j都不为0时

lev_{a,b}(i,j)=min\{lev_{a,b}(i-1,j)+1,lev_{a,b}(i,j-1)+1,lev_{a,b}(i-1,j-1)(if a_i=b_j),lev_{a,b}(i-1,j-1)+1(if a_i\neq b_j)\}

4) 矩阵右下角的3,就是字符串kitten和sitting的编辑距离,即相似度;其斜上方的3,就是子串kitte和sittin的编辑距离,即相似度。

5)当矩阵的第一行和第一列都初始化后,每个子串的编辑距离,都基于其斜上,上和左边的编辑距离通过3)中的公式来计算。比如,看上述矩阵的第四行第六列,它是子串kitt和si的编辑距离 为3,当计算这个值时,首先看斜上方,即kit和s的编辑距离为3,由于a_i \neq b_j,即t和i不同,所以通过3)中的公式计算可得3+1=4;再看上方,即kitt和s的编辑距离为3,kitt和si编辑距离可以通过一步添加操作得到,通过3)中的公式计算可得3+1=4;再看左方,即kit和si的编辑距离为2,kitt和si编辑距离可以通过一步添加操作得到,通过3)中的公式计算可得2+1=3。取三者的最小值,最终kitt和si的编辑距离 为3。

  • Jaccard Similarity

给定两个文本或两句话,把两句话中出现的单词取交集和并集,交集和并集的大小之商即为Jaccard Similarity。

例如:

s1 = "Natural language processing is a promising research area" #8个词
s2 = "More and more researchers are working on natural language processing nowadays" #11 个词

交集:language、processing 2个词。 Jaccard Similarity = 2/(8+11-2) = 0.11764

缺点:只考虑单词出现与否,忽略每个单词的含义,忽略单词顺序,没有考虑单词出现的次数。

  • SimHash

SimHash在搜索引擎中使用比较广泛,当你对关键词进行搜索后,会返回相关的一系列网页,但是互联网上的网页有很多都是高度重复的,所以一个高质量的返回结果,应该不同的,我们不希望返回结果中,前十个网页都是一样的。可以比较一下他们之间的Simhash,返回不同的内容。

1)选择一个hashsize,如32

2)初始化向量V = [0]*32

3) 把一段文本text变成features,如:

可以选择去掉原始文本中的空格,也可以不去。上图中生成的features,其实就是对原始文本,每连续三个字符取一个feature(3元组)。

4)把每个feature(三元组)hash(具体hash算法不做详细展开)成32位,即一个大小为32的向量,向量中的每个值是0/1.

5)对于每个feature的hash结果的每个位置,如果该位置为1就把向量V的对应位置V[i]+1,如果该位置为0就把向量V的对应位置V[i]-1。

6) 最后查看向量V的各个位置,如果V[i]>0则设置V[i]=1;否则设置V[i]=0。最终得到的这个向量V就是这段文本的simhash。

  • 基于文本特征的相似度计算方法

1)将文本转换为feature vectors。

可以采用bag of words得到feature vectors,向量维度为词典大小,向量的每一维是词典中该位置的词在文本中的出现次数,未在文本中出现则为0。

也可以使用TF-IDF得到feature vectors,向量维度为词典大小,向量的每一维是词典中该位置的词在文本计算的TF-IDF值,未在文本中出现则为0。

2)利用feature vectors计算文本间的相似度。

可以使用余弦相似度,基于两个文本的特征向量,计算他们的相似度:

  • word2Vec

词向量可以用于测量单词之间的相似度,相同语义的单词,其词向量也应该是相似的。对词向量做降维并可视化,可以看到如下图所示的聚类效果,即相近语义的词会聚在一起:

文本或句子相似度问题,可以把句子中每个单词的词向量简单做一个平均,得到的向量作为整个句子的向量表示,再利用余弦相似度计算句子的相似度; 也可以对句子中每个单词的词向量做加权平均,权重可以是每个词的TF-IDF值。

3. 实战:基于Python实现编辑距离

 

def editDistDP(s1, s2): 
    m = len(s1)
    n = len(s2)
    # 创建一张表格记录所有子问题的答案
    dp = [[0 for x in range(n+1)] for x in range(m+1)] 
  
    # 从上往下填充DP表格
    for i in range(m+1): 
        for j in range(n+1): 
  
            # 如果第一个字符串为空,唯一的编辑方法就是添加第二个字符串
            if i == 0: 
                dp[i][j] = j    # Min. operations = j 
  
            # 如果第二个字符串为空,唯一的方法就是删除第一个字符串中的所有字母
            elif j == 0: 
                dp[i][j] = i    # Min. operations = i 
  
            # 如果两个字符串结尾字母相同,我们就可以忽略最后的字母
            elif s1[i-1] == s2[j-1]: 
                dp[i][j] = dp[i-1][j-1] 
  
            # 如果结尾字母不同,那我们就需要考虑三种情况,取最小的编辑距离
            else: 
                dp[i][j] = 1 + min(dp[i][j-1],        # 添加 
                                   dp[i-1][j],        # 删除
                                   dp[i-1][j-1])    # 替换
  
    return dp[m][n] 
s1 = "natural language processing is a promising research area"
s2 = "more researchers are working on natural language processing nowadays"
editDistDP(s1.split(), s2.split()) #输入为两个句子 以词为单位 .split() 空格切分。汉语需要jieba分词。

ww2 = """
World War II (often abbreviated to WWII or WW2), also known as the Second World War, was a global war that lasted from 1939 to 1945. The vast majority of the world's countries—including all the great powers—eventually formed two opposing military alliances: the Allies and the Axis. A state of total war emerged, directly involving more than 100 million people from over 30 countries. The major participants threw their entire economic, industrial, and scientific capabilities behind the war effort, blurring the distinction between civilian and military resources. World War II was the deadliest conflict in human history, marked by 50 to 85 million fatalities, most of whom were civilians in the Soviet Union and China. It included massacres, the genocide of the Holocaust, strategic bombing, premeditated death from starvation
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值