#!/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()
