前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用python比较两篇文章的相似度以判断重复度

用python比较两篇文章的相似度以判断重复度

原创
作者头像
mariolu
修改2023-12-22 10:01:45
2430
修改2023-12-22 10:01:45
举报

文档相似度判断方法有很多种,比如说余弦相似度,ngram和著名的tf-idf方法去计算文本相似度。

本文以最简单比较好理解的余弦相似度,用python实操如何比较两段文字的相似度。

一、余弦相似度

使用余弦相似度来计算不同文档之间的相似度。

1.1 基本数学公式

假设有两个向量 b和a:

那么点积的定义是两个向量相加的每个分量的简单乘法。

两个向量之间的点积的结果不是另一个向量,而是一个值,即标量。

那这个例子为计算出0。它的背后含义是什么?我们再深入了解点积的几何定义是什么:

重新排列方程:

那么,这个术语

是向量a到向量b的投影,如下图所示:

当两个不同向量之间的点积为零时,它们彼此正交(角度为 90 度)。

这里使用的是 2D 示例,但其实,还可以计算更高维空间中向量之间的角度和相似性,这就是数学让我们看到的远不止显而易见的东西。

1.2 余弦相似性

两个向量之间的余弦相似度是计算它们之间角度的余弦的度量。这个指标是方向的度量,而不是量级,它可以看作是归一化空间上文档之间的比较,除了文档的每个字数 (tf-idf) 的大小,这里余弦相似度考虑文档之间的角度。余弦相似度公式:

余弦相似度将生成一个指标,通过查看角度而不是大小来表示两个文档的相关性,如以下示例所示:

不同文档的余弦相似度值为 1(方向相同)、0(90 度)、-1(方向相反)。

1.3 word出现频次

即使有一个向量指向一个远离另一个向量的点,它们仍然可以有一个小角度,这是使用余弦相似性的中心点,测量往往会忽略文档上的较高项数。假设我们有一个单词“sky”出现 200 次的文档,另一个单词“sky”出现 50 次的文档,它们之间的欧几里得距离会更高,但角度仍然很小,因为它们指向同一个方向。所以考察word出现的次数对比较文档也很重要。

那么文档的向量空间模型(如下图所示),该模型被建模为向量(具有TF-IDF计数),并且还有一个公式来计算该空间中不同文档之间的相似性。

二、python实操

我们使用numpy来演示两段文档的余弦相似度

2.1 文档向量化

在此之前,我们需要对文字进行分词处理。

  • sent1 ="this is a foo bar"
  • sent2 ="foo bar bar black sheep"
  • sent3 ="this is a sentence"

比如这里有三句话,那么我们会建立一个词典库包含这三句话出现的所有单词。

那么要建的词典库就是vocab= ['a', 'bar', 'black', 'foo', 'is', 'sentence', 'sheep', 'this']

这三句话对应的n维向量(这里n=8,就是词典库的个数)就是

  • sent1= ('this is a foo bar', [1, 1, 0, 1, 1, 0, 0, 1])
  • sent2= ('foo bar bar black sheep', [0, 2, 1, 1, 0, 0, 1, 0])
  • sent3=('this is a sentence', [1, 0, 0, 0, 1, 1, 0, 1])]

其中如果该句子出现了某个word,那么计次数1,出现多次则计出现的次数。

对句子向量化之后,就可以计算每两个句子的相似度。

2.2 对向量计算余弦相似度

完整的程序如下:

代码语言:python
复制
import numpy as np
from math import sqrt, log
from itertools import chain, product
from collections import defaultdict

def cosine_sim(u,v):
    return np.dot(u,v) / (sqrt(np.dot(u,u)) * sqrt(np.dot(v,v)))


def corpus2vectors(corpus):
    def vectorize(sentence, vocab):
        return [sentence.split().count(i) for i in vocab]
    vectorized_corpus = []
    vocab = sorted(set(chain(*[i.lower().split() for i in corpus])))
    for i in corpus:
        vectorized_corpus.append((i, vectorize(i, vocab)))
    return vectorized_corpus, vocab


def create_test_corpus():
    sent1 = "this is a foo bar"
    sent2 = "foo bar bar black sheep"
    sent3 = "this is a sentence"

    all_sents = [sent1,sent2,sent3]
    corpus, vocab = corpus2vectors(all_sents)
    return corpus, vocab

def test_cosine():
    corpus, vocab = create_test_corpus()

    for sentx, senty in product(corpus, corpus):
        print(sentx[0])
        print(senty[0])
        print("cosine =", cosine_sim(sentx[1], senty[1]))
        #print

#print "Testing cosine..."
test_cosine()

输出结果如下:(0为不相关,1为一样,数字越大表示相似度越大):

例子1:

this is a foo bar

this is a foo bar

cosine = 0.9999999999999998

例子2:

this is a foo bar

foo bar bar black sheep

cosine = 0.5070925528371099

例子3:

this is a foo bar

this is a sentence

cosine = 0.6708203932499369

例子4:

foo bar bar black sheep

this is a foo bar

cosine = 0.5070925528371099

例子5:

foo bar bar black sheep

foo bar bar black sheep

cosine = 0.9999999999999999

例子6:

foo bar bar black sheep

this is a sentence

cosine = 0.0

例子7:

this is a sentence

this is a foo bar

cosine = 0.6708203932499369

例子8:

this is a sentence

foo bar bar black sheep

cosine = 0.0

例子9:

this is a sentence

this is a sentence

cosine = 1.0

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、余弦相似度
    • 1.1 基本数学公式
      • 1.2 余弦相似性
        • 1.3 word出现频次
        • 二、python实操
          • 2.1 文档向量化
            • 2.2 对向量计算余弦相似度
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档