文章相似度計算
演算法思路
首先看個簡單的例子:
句子A: 我喜歡看電視,不喜歡看電影
句子B: 我不喜歡看電影,也不喜歡看電視
基本思路
如果兩句話的用詞越相似,它們的內容越相似。因此,可以從詞頻入手,計算它們的相似度。
-
第一步分詞
分詞.png
-
合併所有詞
合併.png
-
計算詞頻
詞頻.png
-
得出詞頻向量
詞頻向量.png
我們可以把它們想象成空間中的兩條線段,都是從原點([0, 0, ...])出發,指向不同的方向。兩條線段之間形成一個夾角,如果夾角為0度,意味著方向相同、線段重合;如果夾角為90度,意味著形成直角,方向完全不相似;如果夾角為180度,意味著方向正好相反。
因此,我們可以通過夾角的大小,來判斷向量的相似程度。夾角越小,就代表越相似。

夾角.png
假定a向量是[x1, y1],b向量是[x2, y2],那麼可以將餘弦定理改寫成下面的形式:

餘弦定理.png
餘弦的這種計算方法對n維向量也成立。假定A和B是兩個n維向量,A是 [A1, A2, ..., An] ,B是 [B1, B2, ..., Bn] ,則A與B的夾角θ的餘弦等於:

n維向量.png
使用這個公式,我們就可以得到,句子A與句子B的夾角的餘弦。

image.png
實踐
計算國務院政府工作和地方政府工作報告相似度
思路:
(1) 使用python中的結巴分詞對國務院報告、省級、縣級政府報告進行分詞,去掉停用詞,並統計詞頻。
(2) 抽取出國務院政府報告與其他省、縣級政府報告的關鍵詞合成一個集合。
(3) 出現頻率最高的前1000個詞,生成國務院報告所對應的特徵向量。
(4) 出現頻率最高的前1000個詞,生成各級報告所對應的特徵向量。
(5) 計算國務院報告的特徵向量與各級政府報告特徵向量的餘弦相似度,值越大越相似。 看各地方的遵從程度。
以安徽省2014-2018年政府工作報告和2014-2018年國務院政府工作報告為例:
程式碼介紹:
- 獲取分詞結果
def jieba_result(content): ''' 獲取jieba分詞結果,並去掉中文符號 :param content: 為read_file返回的文章內容 :return: ''' res = jieba.lcut(content) for i in remove_list(): while i in res: res.remove(i) # print(res) return res
根據python第三方庫jieba,獲取分詞結果。
舉個例子:
import jieba s ="我想要有一個女朋友,傷心。" res = jieba.lcut(s) print(res) ---- ['我', '想要', '有', '一個', '女朋友', ',', '傷心', '。']
由於分詞時,會將一些中文標點符號也分出來,所以定義了一個 remove_list,將在裡面的符號都刪掉
def remove_list(): ''' 將下列列表的中午符號過濾 如果有缺失,可自行新增 :return: ''' remove_list = [',', ':', '。', '《', '》', '\n', '—', '“', '”', '、', ' '] return remove_list
- 獲得前1000的向量
def top_n(res,res_all,n): ''' 獲得分詞的Top n 詞頻,得出詞頻向量 :param res: jieba_res安徽jieba_res 國務院 :param res_all: 合併後的報告 :param n: :return: ''' dic={} for i in res_all: if i not in res: dic[i]=0 else: dic[i]=res.count(i) sort_res= sorted(dic.items(), key=lambda x: x[1], reverse=True) #排序 top_n = sort_res[:n]#獲取Top n # print(top_n) top_n_res=[] for i in top_n: top_n_res.append(i[1]) # print(top_n_res) return top_n_res
統計省工作報告,前1000熱詞的向量和國務院前1000熱詞的向量
- 計算相似度
def CalculateCos(gwyList, subList): ''' 根據兩個詞頻向量,算出cos值 :param gwyList: :param subList: :return: ''' gwyLen = 0 for gwynum in gwyList: gwyLen = gwyLen + gwynum ** 2 gwyLen = gwyLen ** 0.5 subLen = 0 for sub in subList: subLen = subLen + sub ** 2 subLen = subLen ** 0.5 # return subLen totalLen = len(gwyList) fenmu = 0 for i in range(0,totalLen): fenmu = fenmu + subList[i] * gwyList[i] print(fenmu / (subLen * gwyLen)) return fenmu / (subLen * gwyLen)
最終計算2014-2018年每年,安徽省工作報告和國務院工作報告相似度如下:

相似度.png
相似度驚人的高,哈哈哈哈哈。。。。
最後社會主義核心價值觀鎮樓

image.png