基於TF-IDF、餘弦相似度算法實現文本相似度算法的Python應用

基於TF-IDF、餘弦相似度算法實現文本相似度算法的Python應用

基於TF-IDF算法、餘弦相似度算法實現相似文本推薦——文本相似度算法,主要應用於文本聚類、相似文本推薦等場景。

設計說明

  1. 使用jieba切詞,設置自定義字典
  2. 使用TF-IDF算法,找出文章的關鍵詞;
  3. 每篇文章各取出若干個關鍵詞(比如20個),合併成一個集合,計算每篇文章對於這個集合中的詞的詞頻(待優化:為了避免文章長度的差異,可以使用相對詞頻,);
  4. 生成兩篇文章各自的詞頻向量;
  5. 計算兩個向量的餘弦相似度,值越大就表示越相似。

實現說明

1)初始化

需要對原始文檔做些簡單的處理,在預處理結果文件中每一行記錄一個文檔,文檔ID與文檔內容通過一定分隔符分割(比如以:::間隔),寫入txt文檔,當然並非一定如此處理,此處可以根據實際使用,調整代碼實現。

我選取了五則新聞,其中1,2,3為房地產板塊新聞,4,5為NBA板塊新聞。

基於TF-IDF、餘弦相似度算法實現文本相似度算法的Python應用

原始文本預處理

其餘初始化內容詳見代碼註釋。

class DocumentSimilarity:
def __init__(self):

#停詞字典路徑
self.stopword = 'Cstopword.dic'
#原始文檔路徑,每一行一個文檔,文檔ID與文檔內容以:::間隔
self.DocumentFilePath = 'Document.txt'
#切詞結果存放路徑
self.CutWordFilePath = 'CutWordNews.txt'
#每個文檔選取關鍵詞個數
self.KeyWordsNum = 10
#推薦相似文檔個數
self.DocumentSimilarityNum = 6
#切詞結果,格式為{文檔ID:切詞結果,……}
self.CutWordDict = {}
#文檔關鍵詞字典,格式為{文檔ID:{關鍵詞:TF-IDF值,……},……}
self.DocumentKeywords = {}
#文檔詞頻字典,格式為{文檔ID:{切詞:詞頻,……},……}
self.WordsFrequency = {}
# 導入自定義字典
jieba.load_userdict("Custom_dictionary.dic")

2)使用jieba切詞

之前在 文章中已詳細介紹過,這裡不做贅述。

def CutWord(self):
"""
切詞
:return:
"""
stopwords = [line.strip().decode('utf-8') for line in open(self.stopword).readlines()] # 讀取中文停用詞表
with open(self.DocumentFilePath, 'r+') as readfile:
content = readfile.readlines() #讀取文本內容
with open(self.CutWordFilePath, 'w+') as writerfile:
for line in content:
cut_words = jieba.cut(line.split(':::')[1]) #分詞,默認是精確分詞
tmp = []
for word in cut_words:
word = ''.join(re.findall(u'[\\u4e00-\\u9fa5]|[0-9]+', word)).strip() # 過濾不是中文、數字的內容
if (len(word) != 0 and not stopwords.__contains__(word)): # 去掉在停用詞表中出現的內容
tmp.append(word)
writerfile.write('\t'.join(tmp).encode('utf-8') + "\n")
self.CutWordDict[line.split(':::')[0]] = '\t'.join(tmp).encode('utf-8')

基於TF-IDF、餘弦相似度算法實現文本相似度算法的Python應用

結巴分詞結果

3)使用TF-IDF算法,找出文章的關鍵詞

TF-IDF(term frequency–inverse document frequency)是一種用於信息檢索與數據挖掘的常用加權技術。用以評估一字詞對於一個文件集或一個語料庫中的其中一份文件的重要程度。字、詞語的重要性隨著它在文件中出現的次數成正比增加,但同時會隨著它在語料庫中出現的頻率成反比下降。即如果某個詞或短語在一篇文章中出現的頻率(TF)高,並且在整個語料庫章中很少出現,則認為此詞或者短語具有很好的類別區分能力,適合提取為文檔關鍵字。

  • 計算詞頻

詞頻 = 某個詞在文章中出現的總次數/文章的總詞數

  • 計算逆文檔頻率

在此,首先需要一個語料庫來模擬語言的使用環境。

逆文檔頻率(IDF) = log(詞料庫的文檔總數/包含該詞的文檔數+1)

  • 計算TF-IDF值

TF-IDF值 = TF * IDF(TF-IDF值與該詞的出現頻率成正比,與在整個語料庫中的出現次數成反比)

  • 排序取關鍵字

計算出文章中每個詞的TF-IDF值之後,進行排序,選取其中值最高的幾個作為關鍵字。

def GetKeyWords(self):
"""
獲取文檔關鍵詞
:return:
"""
vectorizer = CountVectorizer() # 將文本中的詞語轉換為詞頻矩陣 矩陣元素a[i][j] 表示j詞在i類文本下的詞頻 http://scikit-learn.org/stable/modules/feature_extraction.html
FrequencyMatrix = vectorizer.fit_transform(self.CutWordDict.values()) #返回詞頻矩陣
transformer = TfidfTransformer()
TFIDF = transformer.fit_transform(FrequencyMatrix) # 第一個fit_transform是計算tf-idf 第二個fit_transform是將文本轉為詞頻矩陣,
AllWord = vectorizer.get_feature_names()
Weight = TFIDF.toarray() # tf-idf矩陣,元素w[i][j]表示j詞在i類文本中的tf-idf權重
Title = self.CutWordDict.keys()
self.WordsFrequency = {}

for i in range(len(Weight)): #打印每類文本的tf-idf詞語權重,第一個for遍歷所有文本,第二個for便利某一類文本下的詞語權重
tmp ={}
for j in range(len(AllWord)):
if Weight[i][j] != 0.0:
tmp[AllWord[j]] = Weight[i][j]


sortdict = dict(sorted(tmp.items(), key=lambda d: d[1], reverse=True)[:self.KeyWordsNum])
self.DocumentKeywords[Title[i]] = sortdict #獲取每篇文章的關鍵詞
wordsFrequencyTmp = {}
for word in AllWord:
y = vectorizer.vocabulary_.get(word)
WordFrequency = FrequencyMatrix.toarray()[i][y]
if WordFrequency != 0:
wordsFrequencyTmp[word] = WordFrequency
self.WordsFrequency[Title[i]] = wordsFrequencyTmp
基於TF-IDF、餘弦相似度算法實現文本相似度算法的Python應用

4)生成兩篇文章各自的詞頻向量,計算兩個向量的餘弦相似度,值越大就表示越相似。

@staticmethod
def Cos(cipin):
"""
餘弦計算,返回餘弦相似度
:param cipin:詞頻,格式[[1,2],[1,2]]
:return:
"""
dot_product = 0.0
normA = 0.0
normB = 0.0
for x,y in cipin:
dot_product += float(x) * float(y)
normA += float(x) * float(x)
normB += float(y) * float(y)
if normA == 0.0 or normB == 0.0:
return 0
else:
return float(dot_product)/ float(sqrt(normA * normB))

def Cosinesimilarity(self,OneselfTextId):
"""
獲取相似文檔
:param OneselfTextId:文檔ID
:return:
"""
SimilarText ={}
for TextId,Keywords in self.DocumentKeywords.iteritems():
if TextId != OneselfTextId:
Bothtextfrequency = []
K = self.DocumentKeywords[OneselfTextId].keys() + self.DocumentKeywords[TextId].keys()#獲取雙方關鍵詞列表
for keyword in K :#獲取關鍵詞詞頻
if keyword in self.WordsFrequency[OneselfTextId].keys():
FrequencyOneself =self.WordsFrequency[OneselfTextId][keyword]
else:
FrequencyOneself = 0
if keyword in self.WordsFrequency[TextId].keys():
FrequencyOther =self.WordsFrequency[TextId][keyword]
else:
FrequencyOther = 0
Bothtextfrequency.append([FrequencyOneself,FrequencyOther])
Cosinesimilarity = DocumentSimilarity.Cos(Bothtextfrequency)#計算餘弦
SimilarText[TextId] = Cosinesimilarity

SortDict = dict(sorted(SimilarText.items(), key=lambda d: d[1], reverse=True)[:self.DocumentSimilarityNum])

for i,n in sorted(SimilarText.items(), key=lambda d: d[1], reverse=True)[:self.DocumentSimilarityNum]:
print u'【文本ID】:{0},【文本相似度】:{1} 【文本關鍵詞】:{2}|{3}'.format(i ,n,','.join(self.DocumentKeywords[i]),','.join(self.DocumentKeywords[OneselfTextId]))

return SortDict

基於TF-IDF、餘弦相似度算法實現文本相似度算法的Python應用

使用說明

  • 需安裝jieba、sklearn、numpy第三方庫。
import re 

import jieba
import jieba.analyse
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
from numpy import *
  • 尋找與第一則新聞相似的文本內容結果如下:
if __name__ == "__main__":
DS = DocumentSimilarity()
DS.CutWord()
DS.GetKeyWords()
DS.Cosinesimilarity('1')
基於TF-IDF、餘弦相似度算法實現文本相似度算法的Python應用

轉載請說明,若對你有幫助,關注支持一下哦。


分享到:


相關文章: