使用餘弦定理計算文字相似度

2021-09-05 10:40:08 字數 3459 閱讀 4227

文字相似度:

學過向量代數的人都知道,向量實際上是多維空間中有方向的線段。如果兩個向量的方向一致,即夾角接近零,那麼這兩個向量就相近。而要確定兩個向量方向是否一致,這就要用到餘弦定理計算向量的夾角了。

餘弦定理對我們每個人都不陌生,它描述了三角形中任何乙個夾角和三個邊的關係,換句話說,給定三角形的三條邊,我們可以用餘弦定理求出三角形各個角的角度。假定三角形的三條邊為 a, b 和 c,對應的三個角為 a, b 和 c,那麼角 a 的余弦:

如果我們將三角形的兩邊 b 和 c 看成是兩個向量,那麼上述公式等價於:

其中分母表示兩個向量 b 和 c 的長度,分子表示兩個向量的內積。舉乙個具體的例子,假如文字x 和文字 y 對應向量分別是

那麼它們夾角的余弦等於:

當兩個文字向量夾角的余弦等於1時,這兩個文字完全重複;當夾角的余弦接近於一時,兩條新聞相似;夾角的余弦越小,兩條文字越不相關。

假設有下面兩個句子:

第一步:分詞

第二步:列出所有的詞、字

我,喜歡,看,電視,電影,不,也

第三步:計算詞頻

第四步:描述詞頻向量

第五步:計算夾角余弦

使用這個公式,我們就可以得到,句子a與句子b的夾角的余弦。

余弦值越接近1,就表明夾角越接近0度,也就是兩個向量越相似,這就叫」余弦相似性」。所以,上面的句子a和句子b是很相似。

實際使用過程需要注意的事項

#!/usr/bin/env python

# -*- coding: utf-8 -*-

from __future__ import division

import jieba.analyse

from math import sqrt

class similarity():

def __init__(self, target1, target2, topk=10):

self.target1 = target1

self.target2 = target2

self.topk = topk

def vector(self):

self.vdict1 = {}

self.vdict2 = {}

top_keywords1 = jieba.analyse.extract_tags(self.target1, topk=self.topk, withweight=true)

top_keywords2 = jieba.analyse.extract_tags(self.target2, topk=self.topk, withweight=true)

for k, v in top_keywords1:

self.vdict1[k] = v

for k, v in top_keywords2:

self.vdict2[k] = v

def mix(self):

for key in self.vdict1:

self.vdict2[key] = self.vdict2.get(key, 0)

for key in self.vdict2:

self.vdict1[key] = self.vdict1.get(key, 0)

def mapminmax(vdict):

"""計算相對詞頻"""

_min = min(vdict.values())

_max = max(vdict.values())

_mid = _max - _min

#print _min, _max, _mid

for key in vdict:

vdict[key] = (vdict[key] - _min)/_mid

return vdict

self.vdict1 = mapminmax(self.vdict1)

self.vdict2 = mapminmax(self.vdict2)

def similar(self):

self.vector()

self.mix()

sum = 0

for key in self.vdict1:

sum += self.vdict1[key] * self.vdict2[key]

a = sqrt(reduce(lambda x,y: x+y, map(lambda x: x*x, self.vdict1.values())))

b = sqrt(reduce(lambda x,y: x+y, map(lambda x: x*x, self.vdict2.values())))

return sum/(a*b)

if __name__ == '__main__':

t1 = '''餘弦定理和新聞的分類似乎是兩件八桿子打不著的事,但是它們確有緊密的聯絡。具體說,新聞的分類很大程度上依靠餘弦定理。google 的新聞是自動分類和整理的。所謂新聞的分類無非是要把相似的新聞放到一類中。計算機其實讀不懂新聞,它只能快速計算。這就要求我們設計乙個演算法來算出任意兩篇新聞的相似性。為了做到這一點,我們需要想辦法用一組數字來描述一篇新聞。我們來看看怎樣找一組數字,或者說乙個向量來描述一篇新聞。回憶一下我們在「如何度量網頁相關性」一文中介紹的tf/idf 的概念。對於一篇新聞中的所有實詞,我們可以計算出它們的單文字詞彙頻率/逆文字頻率值(tf/idf)。不難想象,和新聞主題有關的那些實詞頻率高,tf/idf 值很大。我們按照這些實詞在詞彙表的位置對它們的 tf/idf 值排序。比如,詞彙表有六萬四千個詞,分別為'''

t2 = '''新聞分類——「計算機的本質上只能做快速運算,為了讓計算機能夠「算」新聞」(而不是讀新聞),就要求我們先把文字的新聞變成一組可計算的數字,然後再設計乙個演算法來算出任何兩篇新聞的相似性。「——具體做法就是算出新聞中每個詞的tf-idf值,然後按照詞彙表排成乙個向量,我們就可以對這個向量進行運算了,那麼如何度量兩個向量?——向量的夾角越小,那麼我們就認為它們更相似,而長度因為字數的不同並沒有太大的意義。——如何計算夾角,那就用到了餘弦定理(公式略)。——如何建立新聞類別的特徵向量,有兩種方法,手工和自動生成。至於自動分類的方法,書本上有介紹,我這裡就略過了。很巧妙,但是我的篇幅肯定是放不下的。除餘弦定理之外,還可以用矩陣的方法對文字進行分類,但這種方法需要迭代很多次,對每個新聞都要兩兩計算,但是在數學上有乙個十分巧妙的方法——奇異值分解(svd)。奇異值分解,就是把上面這樣的大矩陣,分解為三個小矩陣的相乘。這三個小矩陣都有其物理含義。這種方法能夠快速處理超大規模的文字分類,但是結果略顯粗陋,如果兩種方法一前一後結合使用,既能節省時間,又提高了精確性。'''

topk = 10

s = similarity(t1, t2, topk)

print s.similar()

文字相似度演算法 餘弦定理

最近由於工作專案,需要判斷兩個txt文字是否相似,於是開始在網上找資料研究,因為在程式中會把文字轉換成string再做比較,所以最開始找到了這篇關於 距離編輯演算法 blog寫的非常好,受益匪淺。於是我決定把它用到專案中,來判斷兩個文字的相似度。但後來實際操作發現有一些問題 直接說就是查詢一本書中的...

文字相似度 自己實現文字相似度演算法(餘弦定理)

最近由於工作專案,需要判斷兩個txt文字是否相似,於是開始在網上找資料研究,因為在程式中會把文字轉換成string再做比較,所以最開始找到了這篇關於 距離編輯演算法 blog寫的非常好,受益匪淺。於是我決定把它用到專案中,來判斷兩個文字的相似度。但後來實際操作發現有一些問題 直接說就是查詢一本書中的...

文字相似度計算 餘弦定理和廣義Jaccard係數

在7.9餘弦定理 空間向量 我的數學3 中簡單地說了一下利用餘弦定理來計算文字相似度。下面是利用餘弦定理和廣義jaccard係數來計算文字相似度。簡單介紹一下jaccard係數 廣義jaccard係數可以用於文件資料,並在二元屬性情況下歸約為jaccard係數。廣義jaccard係數又稱tanimo...