Python實現(xiàn)中文文本關鍵詞抽取的三種方法
文本關鍵詞抽取,是對文本信息進行高度凝練的一種有效手段,通過3-5個詞語準確概括文本的主題,幫助讀者快速理解文本信息。目前,用于文本關鍵詞提取的主要方法有四種:基于TF-IDF的關鍵詞抽取、基于TextRank的關鍵詞抽取、基于Word2Vec詞聚類的關鍵詞抽取,以及多種算法相融合的關鍵詞抽取。筆者在使用前三種算法進行關鍵詞抽取的學習過程中,發(fā)現(xiàn)采用TF-IDF和TextRank方法進行關鍵詞抽取在網(wǎng)上有很多的例子,代碼和步驟也比較簡單,但是采用Word2Vec詞聚類方法時網(wǎng)上的資料并未把過程和步驟表達的很清晰。因此,本文分別采用TF-IDF方法、TextRank方法和Word2Vec詞聚類方法實現(xiàn)對專利文本(同樣適用于其它類型文本)的關鍵詞抽取,通過理論與實踐相結合的方式,一步步了解、學習、實現(xiàn)中文文本關鍵詞抽取。
1 概述
一篇文檔的關鍵詞等同于最能表達文檔主旨的N個詞語,即對于文檔來說最重要的詞,因此,可以將文本關鍵詞抽取問題轉化為詞語重要性排序問題,選取排名前TopN個詞語作為文本關鍵詞。目前,主流的文本關鍵詞抽取方法主要有以下兩大類:
(1)基于統(tǒng)計的關鍵詞提取方法
該方法根據(jù)統(tǒng)計信息,如詞頻,來計算得到文檔中詞語的權重,按權重值排序提取關鍵詞。TF-IDF和TextRank均屬于此類方法,其中TF-IDF方法通過計算單文本詞頻(Term Frequency, TF)和逆文本頻率指數(shù)(Inverse Document Frequency, IDF)得到詞語權重;TextRank方法基于PageRank的思想,通過詞語共現(xiàn)窗口構建共現(xiàn)網(wǎng)絡,計算詞語得分。此類方法簡單易行,適用性較強,然而未考慮詞序問題。
(2)基于機器學習的關鍵詞提取方法
該方法包括了SVM、樸素貝葉斯等有監(jiān)督學習方法,以及K-means、層次聚類等無監(jiān)督學習方法。在此類方法中,模型的好壞取決于特征提取,而深度學習正是特征提取的一種有效方式。由Google推出的Word2Vec詞向量模型,是自然語言領域中具有代表性的學習工具。它在訓練語言模型的過程中將詞典映射到一個更抽象的向量空間中,每一個詞語通過高維向量表示,該向量空間中兩點之間的距離就對應兩個詞語的相似程度。
基于以上研究,本文分別采用TF-IDF方法、TextRank方法和Word2Vec詞聚類方法,利用Python語言進行開發(fā),實現(xiàn)文本關鍵詞的抽取。
2 開發(fā)環(huán)境準備
2.1 Python環(huán)境
筆者使用的是anaconda環(huán)境下的Python 3.10.13。
2.2 第三方模塊
本實驗實現(xiàn)使用的主要模塊如下所示:
(1)Jieba
目前使用最為廣泛的中文分詞組件。
(2)Gensim
用于主題模型、文檔索引和大型語料相似度索引的python庫,主要用于自然語言處理(NLP)和信息檢索(IR)。 本實例中的維基中文語料處理和中文詞向量模型構建需要用到該模塊。
(3)Pandas
用于高效處理大型數(shù)據(jù)集、執(zhí)行數(shù)據(jù)分析任務的python庫,是基于Numpy的工具包。安裝方法:pip install pandas。
(4)Numpy
用于存儲和處理大型矩陣的工具包。
(5)Scikit-learn
用于機器學習的python工具包,python模塊引用名字為sklearn,安裝前還需要Numpy和Scipy兩個Python庫。本實例中主要用到了該模塊中的feature_extraction、KMeans(k-means聚類算法)和PCA(pac降維算法)。
(6)Matplotlib
Matplotlib是一個python的圖形框架,用于繪制二維圖形。
3 數(shù)據(jù)準備
3.1 樣本語料
文本將汽車行業(yè)的10篇專利作為樣本數(shù)據(jù)集,見文件“data/sample_data.csv”。文件中依順序包含編號(id)、標題(title)和摘要(abstract)三個字段,其中標題和摘要都要參與到關鍵詞的抽取。各位可根據(jù)自己的樣本數(shù)據(jù)進行數(shù)據(jù)讀取相關代碼的調整。
3.2 停用詞詞典
本文使用中科院計算所中文自然語言處理開放平臺發(fā)布的中文停用詞表,包含了1208個停用詞。下載地址:http://www.hicode.cc/download/view-software-13784.html
另外,由于本實例的樣本是專利文本,詞匯專業(yè)性較高,需要人工新增停用詞,可直接在上述停用詞表中添加,一行為一個停用詞,見文件“data/stopWord.txt”。在本例中,筆者在文件最前面人工新增了“包括、相對、免受、用于、本發(fā)明、結合”這六個停用詞,用于示范,各位可根據(jù)實際情況自行刪減或新增停用詞。
4 基于TF-IDF的文本關鍵詞抽取方法
4.1 TF-IDF算法思想
詞頻(Term Frequency,TF)指某一給定詞語在當前文件中出現(xiàn)的頻率。由于同一個詞語在長文件中可能比短文件有更高的詞頻,因此根據(jù)文件的長度,需要對給定詞語進行歸一化,即用給定詞語的次數(shù)除以當前文件的總詞數(shù)。
逆向文件頻率(Inverse Document Frequency,IDF)是一個詞語普遍重要性的度量。即如果一個詞語只在很少的文件中出現(xiàn),表示更能代表文件的主旨,它的權重也就越大;如果一個詞在大量文件中都出現(xiàn),表示不清楚代表什么內容,它的權重就應該小。
TF-IDF的主要思想是,如果某個詞語在一篇文章中出現(xiàn)的頻率高,并且在其他文章中較少出現(xiàn),則認為該詞語能較好的代表當前文章的含義。即一個詞語的重要性與它在文檔中出現(xiàn)的次數(shù)成正比,與它在語料庫中文檔出現(xiàn)的頻率成反比。
計算公式如下:

4.2 TF-IDF文本關鍵詞抽取方法流程
由以上可知,TF-IDF是對文本所有候選關鍵詞進行加權處理,根據(jù)權值對關鍵詞進行排序。假設Dn為測試語料的大小,該算法的關鍵詞抽取步驟如下所示:
(1) 對于給定的文本D進行分詞、詞性標注和去除停用詞等數(shù)據(jù)預處理操作。本文采用jieba分詞,保留’n’,‘nz’,‘v’,‘vd’,‘vn’,‘l’,‘a’,'d’這幾個詞性的詞語(‘n’: 名詞,‘nz’: 其他專有名詞,‘v’: 動詞,‘vd’: 副動詞,‘vn’: 名動詞,‘l’: 習用語,‘a’: 形容詞,‘d’: 副詞),最終得到n個候選關鍵詞,即D=[t1,t2,…,tn] ;
(2) 計算詞語ti 在文本D中的詞頻;
(3) 計算詞語ti 在整個語料的IDF=log (Dn /(Dt +1)),Dt 為語料庫中詞語ti 出現(xiàn)的文檔個數(shù);
(4) 計算得到詞語ti 的TF-IDF=TF*IDF,并重復(2)—(4)得到所有候選關鍵詞的TF-IDF數(shù)值;
(5) 對候選關鍵詞計算結果進行倒序排列,得到排名前TopN個詞匯作為文本關鍵詞。
4.3 代碼實現(xiàn)
Python第三方工具包Scikit-learn提供了TFIDF算法的相關函數(shù),本文主要用到了sklearn.feature_extraction.text下的TfidfTransformer和CountVectorizer函數(shù)。其中,CountVectorizer函數(shù)用來構建語料庫的中的詞頻矩陣,TfidfTransformer函數(shù)用來計算詞語的tfidf權值。
注:TfidfTransformer()函數(shù)有一個參數(shù)smooth_idf,默認值是True,若設置為False,則IDF的計算公式為idf=log(Dn /Dt ) + 1。
基于TF-IDF方法實現(xiàn)文本關鍵詞抽取的代碼執(zhí)行步驟如下:
(1)讀取樣本源文件sample_data.csv;
(2)獲取每行記錄的標題和摘要字段,并拼接這兩個字段;
(3)加載自定義停用詞表stopWord.txt,并對拼接的文本進行數(shù)據(jù)預處理操作,包括分詞、篩選出符合詞性的詞語、去停用詞,用空格分隔拼接成文本;
(4)遍歷文本記錄,將預處理完成的文本放入文檔集corpus中;
(5)使用CountVectorizer()函數(shù)得到詞頻矩陣,a[j][i]表示第j個詞在第i篇文檔中的詞頻;
(6)使用TfidfTransformer()函數(shù)計算每個詞的tf-idf權值;
(7)得到詞袋模型中的關鍵詞以及對應的tf-idf矩陣;
(8)遍歷tf-idf矩陣,打印每篇文檔的詞匯以及對應的權重;
(9)對每篇文檔,按照詞語權重值降序排列,選取排名前topN個詞最為文本關鍵詞,并寫入數(shù)據(jù)框中;
(10)將最終結果寫入文件keys_TFIDF.csv中。
源代碼如下:
# 采用TF-IDF方法提取文本關鍵詞
# http://scikit-learn.org/stable/modules/feature_extraction.html#tfidf-term-weighting
import sys,codecs
import pandas as pd
import numpy as np
import jieba.posseg
import jieba.analyse
from sklearn import feature_extraction
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
"""
TF-IDF權重:
1、CountVectorizer 構建詞頻矩陣
2、TfidfTransformer 構建tfidf權值計算
3、文本的關鍵字
4、對應的tfidf矩陣
"""
# 數(shù)據(jù)預處理操作:分詞,去停用詞,詞性篩選
def dataPrepos(text, stopkey):
l = []
pos = ['n', 'nz', 'v', 'vd', 'vn', 'l', 'a', 'd'] # 定義選取的詞性
seg = jieba.posseg.cut(text) # 分詞
for i in seg:
if i.word not in stopkey and i.flag in pos: # 去停用詞 + 詞性篩選
l.append(i.word)
return l
# tf-idf獲取文本top10關鍵詞
#@profile
def getKeywords_tfidf(data,stopkey,topK):
idList, titleList, abstractList = data['id'], data['title'], data['abstract']
corpus = [] # 將所有文檔輸出到一個list中,一行就是一個文檔
for index in range(len(idList)):
text = '%s。%s' % (titleList[index], abstractList[index]) # 拼接標題和摘要
text = dataPrepos(text,stopkey) # 文本預處理
text = " ".join(text) # 連接成字符串,空格分隔
corpus.append(text)
# 1、構建詞頻矩陣,將文本中的詞語轉換成詞頻矩陣
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(corpus) # 詞頻矩陣,a[i][j]:表示j詞在第i個文本中的詞頻
# 2、統(tǒng)計每個詞的tf-idf權值
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(X)
# 3、獲取詞袋模型中的關鍵詞
word = vectorizer.get_feature_names_out()
# 4、獲取tf-idf矩陣,a[i][j]表示j詞在i篇文本中的tf-idf權重
weight = tfidf.toarray()
# 5、打印詞語權重
ids, titles, keys = [], [], []
for i in range(len(weight)):
print("-------這里輸出第", i+1 , "篇文本的詞語tf-idf------")
ids.append(idList[i])
titles.append(titleList[i])
df_word,df_weight = [],[] # 當前文章的所有詞匯列表、詞匯對應權重列表
for j in range(len(word)):
print (word[j],weight[i][j])
df_word.append(word[j])
df_weight.append(weight[i][j])
df_word = pd.DataFrame(df_word,columns=['word'])
df_weight = pd.DataFrame(df_weight,columns=['weight'])
word_weight = pd.concat([df_word, df_weight], axis=1) # 拼接詞匯列表和權重列表
word_weight = word_weight.sort_values(by="weight",ascending = False) # 按照權重值降序排列
keyword = np.array(word_weight['word']) # 選擇詞匯列并轉成數(shù)組格式
word_split = [keyword[x] for x in range(0,topK)] # 抽取前topK個詞匯作為關鍵詞
word_split = " ".join(word_split)
keys.append(word_split)
result = pd.DataFrame({"id": ids, "title": titles, "key": keys},columns=['id','title','key'])
return result
def main():
# 讀取數(shù)據(jù)集
dataFile = 'data/sample_data.csv'
data = pd.read_csv(dataFile)
# 停用詞表
stopkey = [w.strip() for w in codecs.open('data/stopWord.txt', 'r', encoding='utf-8').readlines()]
# tf-idf關鍵詞抽取
result = getKeywords_tfidf(data,stopkey,10)
result.to_csv("result/keys_TFIDF.csv",index=False)
if __name__ == '__main__':
main()
最終運行結果如下圖所示。

5 基于TextRank的文本關鍵詞抽取方法
5.1 PageRank算法思想
TextRank算法是基于PageRank算法的,PageRank算法是Google的創(chuàng)始人拉里·佩奇和謝爾蓋·布林于1998年在斯坦福大學讀研究生期間發(fā)明的,是用于根據(jù)網(wǎng)頁間相互的超鏈接來計算網(wǎng)頁重要性的技術。該算法借鑒了學術界評判學術論文重要性的方法,即查看論文的被引用次數(shù)?;谝陨舷敕ǎ琍ageRank算法的核心思想是,認為網(wǎng)頁重要性由兩部分組成:
① 如果一個網(wǎng)頁被大量其他網(wǎng)頁鏈接到說明這個網(wǎng)頁比較重要,即被鏈接網(wǎng)頁的數(shù)量;
② 如果一個網(wǎng)頁被排名很高的網(wǎng)頁鏈接說明這個網(wǎng)頁比較重要,即被鏈接網(wǎng)頁的權重。
一般情況下,一個網(wǎng)頁的PageRank值(PR)計算公式如下所示:

其中,PR(Pi)是第i個網(wǎng)頁的重要性排名即PR值;ɑ是阻尼系數(shù),一般設置為0.85;N是網(wǎng)頁總數(shù);Mpi 是所有對第i個網(wǎng)頁有出鏈的網(wǎng)頁集合;L(Pj)是第j 個網(wǎng)頁的出鏈數(shù)目。
初始時,假設所有網(wǎng)頁的排名都是1/N,根據(jù)上述公式計算出每個網(wǎng)頁的PR值,在不斷迭代趨于平穩(wěn)的時候,停止迭代運算,得到最終結果。一般來講,只要10次左右的迭代基本上就收斂了。
5.2 TextRank算法思想
TextRank算法是Mihalcea和Tarau于2004年在研究自動摘要提取過程中所提出來的,在PageRank算法的思路上做了改進。該算法把文本拆分成詞匯作為網(wǎng)絡節(jié)點,組成詞匯網(wǎng)絡圖模型,將詞語間的相似關系看成是一種推薦或投票關系,使其可以計算每一個詞語的重要性。
基于TextRank的文本關鍵詞抽取是利用局部詞匯關系,即共現(xiàn)窗口,對候選關鍵詞進行排序,該方法的步驟如下:
(1) 對于給定的文本D進行分詞、詞性標注和去除停用詞等數(shù)據(jù)預處理操作。本文采用結巴分詞,保留’n’,‘nz’,‘v’,‘vd’,‘vn’,‘l’,‘a’,'d’這幾個詞性的詞語,最終得到n個候選關鍵詞,即D=[t1,t2,…,tn] ;
(2) 構建候選關鍵詞圖G=(V,E),其中V為節(jié)點集,由候選關鍵詞組成,并采用共現(xiàn)關系構造任兩點之間的邊,兩個節(jié)點之間僅當它們對應的詞匯在長度為K的窗口中共現(xiàn)則存在邊,K表示窗口大小即最多共現(xiàn)K個詞匯;
(3) 根據(jù)公式迭代計算各節(jié)點的權重,直至收斂;
(4) 對節(jié)點權重進行倒序排列,得到排名前TopN個詞匯作為文本關鍵詞。
說明:Jieba庫中包含jieba.analyse.textrank函數(shù)可直接實現(xiàn)TextRank算法,本文采用該函數(shù)進行實驗。
5.3 代碼實現(xiàn)
基于TextRank方法實現(xiàn)文本關鍵詞抽取的代碼執(zhí)行步驟如下:
(1)讀取樣本源文件sample_data.csv;
(2)獲取每行記錄的標題和摘要字段,并拼接這兩個字段;
(3)加載自定義停用詞表stopWord.txt;
(4)遍歷文本記錄,采用jieba.analyse.textrank函數(shù)篩選出指定詞性,以及topN個文本關鍵詞,并將結果存入數(shù)據(jù)框中;
(5)將最終結果寫入文件keys_TextRank.csv中。
源代碼如下:
# 采用TextRank方法提取文本關鍵詞
import sys
import pandas as pd
import jieba.analyse
"""
TextRank權重:
1、將待抽取關鍵詞的文本進行分詞、去停用詞、篩選詞性
2、以固定窗口大小(默認為5,通過span屬性調整),詞之間的共現(xiàn)關系,構建圖
3、計算圖中節(jié)點的PageRank,注意是無向帶權圖
"""
# 處理標題和摘要,提取關鍵詞
def getKeywords_textrank(data,topK):
idList,titleList,abstractList = data['id'],data['title'],data['abstract']
ids, titles, keys = [], [], []
for index in range(len(idList)):
text = '%s。%s' % (titleList[index], abstractList[index]) # 拼接標題和摘要
jieba.analyse.set_stop_words("data/stopWord.txt") # 加載自定義停用詞表
print("\"",titleList[index],"\" , 10 Keywords - TextRank :")
keywords = jieba.analyse.textrank(text, topK=topK, allowPOS=('n','nz','v','vd','vn','l','a','d')) # TextRank關鍵詞提取,詞性篩選
word_split = " ".join(keywords)
print(word_split)
keys.append(word_split)
ids.append(idList[index])
titles.append(titleList[index])
result = pd.DataFrame({"id": ids, "title": titles, "key": keys}, columns=['id', 'title', 'key'])
return result
def main():
dataFile = 'data/sample_data.csv'
data = pd.read_csv(dataFile,encoding='utf-8')
result = getKeywords_textrank(data,10)
result.to_csv("result/keys_TextRank.csv",index=False,encoding='utf-8')
if __name__ == '__main__':
main()
最終運行結果如下圖所示。

6 基于Word2Vec詞聚類的文本關鍵詞抽取方法
6.1 Word2Vec詞向量表示
眾所周知,機器學習模型的輸入必須是數(shù)值型數(shù)據(jù),文本無法直接作為模型的輸入,需要首先將其轉化成數(shù)學形式?;赪ord2Vec詞聚類方法正是一種機器學習方法,需要將候選關鍵詞進行向量化表示,因此要先構建Word2Vec詞向量模型,從而抽取出候選關鍵詞的詞向量。
Word2Vec是當時在Google任職的Mikolov等人于2013年發(fā)布的一款詞向量訓練工具,一經(jīng)發(fā)布便在自然語言處理領域得到了廣泛的應用。該工具利用淺層神經(jīng)網(wǎng)絡模型自動學習詞語在語料庫中的出現(xiàn)情況,把詞語嵌入到一個高維的空間中,通常在100-500維,在新的高維空間中詞語被表示為詞向量的形式。與傳統(tǒng)的文本表示方式相比,Word2Vec生成的詞向量表示,詞語之間的語義關系在高維空間中得到了較好的體現(xiàn),即語義相近的詞語在高維空間中的距離更近;同時,使用詞向量避免了詞語表示的“維度災難”問題。
就實際操作而言,特征詞向量的抽取是基于已經(jīng)訓練好的詞向量模型,詞向量模型的訓練需要海量的語料才能達到較好的效果,而wiki中文語料是公認的大型中文語料,本文擬從wiki中文語料生成的詞向量中抽取本文語料的特征詞向量。Wiki中文語料的Word2vec模型訓練在文章“利用Python實現(xiàn)wiki中文語料的word2vec模型構建”(https://github.com/gmh1627/Wiki_Zh_Word2vec_Python3) 中做了詳盡的描述,在此不贅述。即本文從文章最后得到的文件“wiki.zh.text.vector”中抽取候選關鍵詞的詞向量作為聚類模型的輸入。
另外,在閱讀資料的過程中發(fā)現(xiàn),有些十分專業(yè)或者生僻的詞語可能wiki中文語料中并未包含,為了提高語料的質量,可新增實驗所需的樣本語料一起訓練,筆者認為這是一種十分可行的方式。本例中為了簡便并未采取這種方法,各位可參考此種方法根據(jù)自己的實際情況進行調整。
6.2 K-means聚類算法
聚類算法旨在數(shù)據(jù)中發(fā)現(xiàn)數(shù)據(jù)對象之間的關系,將數(shù)據(jù)進行分組,使得組內的相似性盡可能的大,組件的相似性盡可能的小。
K-Means是一種常見的基于原型的聚類技術,本文選擇該算法作為詞聚類的方法。其算法思想是:首先隨機選擇K個點作為初始質心,K為用戶指定的所期望的簇的個數(shù),通過計算每個點到各個質心的距離,將每個點指派到最近的質心形成K個簇,然后根據(jù)指派到簇的點重新計算每個簇的質心,重復指派和更新質心的操作,直到簇不發(fā)生變化或達到最大的迭代次數(shù)則停止。
6.3 Word2Vec詞聚類文本關鍵詞抽取方法流程
Word2Vec詞聚類文本關鍵詞抽取方法的主要思路是對于用詞向量表示的文本詞語,通過K-Means算法對文章中的詞進行聚類,選擇聚類中心作為文章的一個主要關鍵詞,計算其他詞與聚類中心的距離即相似度,選擇topN個距離聚類中心最近的詞作為文本關鍵詞,而這個詞間相似度可用Word2Vec生成的向量計算得到。
假設Dn為測試語料的大小,使用該方法進行文本關鍵詞抽取的步驟如下所示:
(1) 對Wiki中文語料進行Word2vec模型訓練,參考文章“利用Python實現(xiàn)wiki中文語料的word2vec模型構建”(https://github.com/gmh1627/Wiki_Zh_Word2vec_Python3) ,得到詞向量文件“wiki.zh.text.vector”;
(2) 對于給定的文本D進行分詞、詞性標注、去重和去除停用詞等數(shù)據(jù)預處理操作。本分采用結巴分詞,保留’n’,‘nz’,‘v’,‘vd’,‘vn’,‘l’,‘a’,'d’這幾個詞性的詞語,最終得到n個候選關鍵詞,即D=[t1,t2,…,tn] ;
(3) 遍歷候選關鍵詞,從詞向量文件中抽取候選關鍵詞的詞向量表示,即WV=[v1,v2,…,vm];
(4) 對候選關鍵詞進行K-Means聚類,得到各個類別的聚類中心;
(5) 計算各類別下,組內詞語與聚類中心的距離(歐幾里得距離),按聚類大小進行升序排序;
(6) 對候選關鍵詞計算結果得到排名前TopN個詞匯作為文本關鍵詞。
步驟(4)中需要人為給定聚類的個數(shù),本文測試語料是汽車行業(yè)的專利文本,因此只需聚為1類,各位可根據(jù)自己的數(shù)據(jù)情況進行調整;步驟(5)中計算各詞語與聚類中心的距離,常見的方法有歐式距離和曼哈頓距離,本文采用的是歐式距離,計算公式如下:

6.4 代碼實現(xiàn)
Python第三方工具包Scikit-learn提供了K-Means聚類算法的相關函數(shù),本文用到了sklearn.cluster.KMeans()函數(shù)執(zhí)行K-Means算法,sklearn.decomposition.PCA()函數(shù)用于數(shù)據(jù)降維以便繪制圖形。
基于Word2Vec詞聚類方法實現(xiàn)文本關鍵詞抽取的代碼執(zhí)行步驟如下:
(1)讀取樣本源文件sample_data.csv;
(2)獲取每行記錄的標題和摘要字段,并拼接這兩個字段;
(3)加載自定義停用詞表stopWord.txt,并對拼接的文本進行數(shù)據(jù)預處理操作,包括分詞、篩選出符合詞性的詞語、去重、去停用詞,形成列表存儲;
(4)讀取詞向量模型文件’wiki.zh.text.vector’,從中抽取出所有候選關鍵詞的詞向量表示,存入文件中;
(5)讀取文本的詞向量表示文件,使用KMeans()函數(shù)得到聚類結果以及聚類中心的向量表示;
(6)采用歐式距離計算方法,計算得到每個詞語與聚類中心的距離;
(7)按照得到的距離升序排列,選取排名前topN個詞作為文本關鍵詞,并寫入數(shù)據(jù)框中;
(8)將最終結果寫入文件keys_word2vec.csv中。
源代碼1如下:
# 采用Word2Vec詞聚類方法抽取關鍵詞1——獲取文本詞向量表示
import warnings
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim') # 忽略警告
import sys, codecs
import pandas as pd
import numpy as np
import jieba
import jieba.posseg
import gensim
# 返回特征詞向量
def getWordVecs(wordList, model):
name = []
vecs = []
for word in wordList:
word = word.replace('\n', '')
try:
if word in model: # 模型中存在該詞的向量表示
name.append(word)
vecs.append(model[word])
except KeyError:
continue
a = pd.DataFrame(name, columns=['word'])
b = pd.DataFrame(np.array(vecs, dtype='float'))
return pd.concat([a, b], axis=1)
# 數(shù)據(jù)預處理操作:分詞,去停用詞,詞性篩選
def dataPrepos(text, stopkey):
l = []
pos = ['n', 'nz', 'v', 'vd', 'vn', 'l', 'a', 'd'] # 定義選取的詞性
seg = jieba.posseg.cut(text) # 分詞
for i in seg:
if i.word not in l and i.word not in stopkey and i.flag in pos: # 去重 + 去停用詞 + 詞性篩選
# print i.word
l.append(i.word)
return l
# 根據(jù)數(shù)據(jù)獲取候選關鍵詞詞向量
def buildAllWordsVecs(data, stopkey, model):
idList, titleList, abstractList = data['id'], data['title'], data['abstract']
for index in range(len(idList)):
id = idList[index]
title = titleList[index]
abstract = abstractList[index]
l_ti = dataPrepos(title, stopkey) # 處理標題
l_ab = dataPrepos(abstract, stopkey) # 處理摘要
# 獲取候選關鍵詞的詞向量
words = np.append(l_ti, l_ab) # 拼接數(shù)組元素
words = list(set(words)) # 數(shù)組元素去重,得到候選關鍵詞列表
wordvecs = getWordVecs(words, model) # 獲取候選關鍵詞的詞向量表示
# 詞向量寫入csv文件,每個詞400維
data_vecs = pd.DataFrame(wordvecs)
data_vecs.to_csv('result/vecs/wordvecs_' + str(id) + '.csv', index=False)
print("document ", id, " well done.")
def main():
# 讀取數(shù)據(jù)集
dataFile = 'data/sample_data.csv'
data = pd.read_csv(dataFile)
# 停用詞表
stopkey = [w.strip() for w in codecs.open('data/stopWord.txt', 'r').readlines()]
# 詞向量模型
inp = 'wiki.zh.text.vector'
model = gensim.models.KeyedVectors.load_word2vec_format(inp, binary=False)
buildAllWordsVecs(data, stopkey, model)
if __name__ == '__main__':
main()
源代碼2如下:
# 采用Word2Vec詞聚類方法抽取關鍵詞2——根據(jù)候選關鍵詞的詞向量進行聚類分析
import sys,os
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import math
import os
# 對詞向量采用K-means聚類抽取TopK關鍵詞
def getkeywords_kmeans(data,topK):
words = data["word"] # 詞匯
vecs = data.iloc[:,1:] # 向量表示
kmeans = KMeans(n_clusters=1,n_init=10,random_state=10).fit(vecs)
labels = kmeans.labels_ #類別結果標簽
labels = pd.DataFrame(labels,columns=['label'])
new_df = pd.concat([labels,vecs],axis=1)
df_count_type = new_df.groupby('label').size() #各類別統(tǒng)計個數(shù)
# print df_count_type
vec_center = kmeans.cluster_centers_ #聚類中心
# 計算距離(相似性) 采用歐幾里得距離(歐式距離)
distances = []
vec_words = np.array(vecs) # 候選關鍵詞向量,dataFrame轉array
vec_center = vec_center[0] # 第一個類別聚類中心,本例只有一個類別
length = len(vec_center) # 向量維度
for index in range(len(vec_words)): # 候選關鍵詞個數(shù)
cur_wordvec = vec_words[index] # 當前詞語的詞向量
dis = 0 # 向量距離
for index2 in range(length):
dis += (vec_center[index2]-cur_wordvec[index2])*(vec_center[index2]-cur_wordvec[index2])
dis = math.sqrt(dis)
distances.append(dis)
distances = pd.DataFrame(distances,columns=['dis'])
result = pd.concat([words, labels ,distances], axis=1) # 拼接詞語與其對應中心點的距離
result = result.sort_values(by="dis",ascending = True) # 按照距離大小進行升序排序
"""
# 將用于聚類的數(shù)據(jù)的特征維度降到2維
pca = PCA(n_components=2)
new_pca = pd.DataFrame(pca.fit_transform(new_df))
print(new_pca)
# 可視化
d = new_pca[new_df['label'] == 0]
plt.plot(d[0],d[1],'r.')
d = new_pca[new_df['label'] == 1]
plt.plot(d[0], d[1], 'go')
d = new_pca[new_df['label'] == 2]
plt.plot(d[0], d[1], 'b*')
plt.gcf().savefig('kmeans.png')
plt.show()
"""
# 抽取排名前topK個詞語作為文本關鍵詞
wordlist = np.array(result['word']) # 選擇詞匯列并轉成數(shù)組格式
word_split = [wordlist[x] for x in range(0,topK)] # 抽取前topK個詞匯
word_split = " ".join(word_split)
return word_split
def main():
# 讀取數(shù)據(jù)集
dataFile = 'data/sample_data.csv'
articleData = pd.read_csv(dataFile,encoding='utf-8')
ids, titles, keys = [], [], []
rootdir = "result/vecs" # 詞向量文件根目錄
fileList = os.listdir(rootdir) #列出文件夾下所有的目錄與文件
# 遍歷文件
for i in range(len(fileList)):
filename = fileList[i]
path = os.path.join(rootdir,filename)
if os.path.isfile(path):
data = pd.read_csv(path, encoding='utf-8') # 讀取詞向量文件數(shù)據(jù)
artile_keys = getkeywords_kmeans(data,10) # 聚類算法得到當前文件的關鍵詞
# 根據(jù)文件名獲得文章id以及標題
(shortname, extension) = os.path.splitext(filename) # 得到文件名和文件擴展名
t = shortname.split("_")
article_id = int(t[len(t)-1]) # 獲得文章id
artile_tit = articleData[articleData.id==article_id]['title'] # 獲得文章標題
artile_tit = list(artile_tit)[0] # series轉成字符串
ids.append(article_id)
titles.append(artile_tit)
keys.append(artile_keys)
# 所有結果寫入文件
result = pd.DataFrame({"id": ids, "title": titles, "key": keys}, columns=['id', 'title', 'key'])
result = result.sort_values(by="id",ascending=True) # 排序
result.to_csv("result/keys_word2vec.csv", index=False,encoding='utf-8')
if __name__ == '__main__':
main()
最終運行結果如下圖所示。

7 結語
本文總結了三種常用的抽取文本關鍵詞的方法:TF-IDF、TextRank和Word2Vec詞向量聚類,并做了原理、流程以及代碼的詳細描述。因本文使用的測試語料較為特殊且數(shù)量較少,未做相應的結果分析,根據(jù)觀察可以發(fā)現(xiàn),得到的十個文本關鍵詞都包含有文本的主旨信息,其中TF-IDF和TextRank方法的結果較好,Word2Vec詞向量聚類方法的效果不佳,這與文獻[8]中的結論是一致的。文獻[8]中提到,對單文檔直接應用Word2Vec詞向量聚類方法時,選擇聚類中心作為文本的關鍵詞本身就是不準確的,因此與其距離最近的N個詞語也不一定是關鍵詞,因此用這種方法得到的結果效果不佳;而TextRank方法是基于圖模型的排序算法,在單文檔關鍵詞抽取方面有較為穩(wěn)定的效果,因此較多的論文是在TextRank的方法上進行改進而提升關鍵詞抽取的準確率。
另外,本文的實驗目的主要在于講解三種方法的思路和流程,實驗過程中的某些細節(jié)仍然可以改進。例如Word2Vec模型訓練的原始語料可加入相應的專業(yè)性文本語料;標題文本往往包含文檔的重要信息,可對標題文本包含的詞語給予一定的初始權重;測試數(shù)據(jù)集可采集多個分類的長文本,與之對應的聚類算法KMeans()函數(shù)中的n_clusters參數(shù)就應當設置成分類的個數(shù);根據(jù)文檔的分詞結果,去除掉所有文檔中都包含某一出現(xiàn)頻次超過指定閾值的詞語;等等。各位可根據(jù)自己的實際情況或者參考論文資料進行參數(shù)的優(yōu)化以及細節(jié)的調整,歡迎給我留言或者私信討論,大家一起共同學習。
至此,利用Pyhon實現(xiàn)中文文本關鍵詞抽取的三種方法全部介紹完畢,測試數(shù)據(jù)、代碼和運行結果已上傳至本人的GitHub倉庫。項目文件為keyword_extraction,data文件夾中包含停用詞表stopWord.txt和測試集sample_data.csv,result文件夾包含三種方法的實驗結果和每篇文檔對應的詞向量文件(vecs)。文中若存在不正確的地方,歡迎各位朋友批評指正!本文是在https://github.com/AimeeLee77/keyword_extraction 的基礎上加以修改的(原文用的是python 2.7),在此對原作者深表感謝!
以上就是Python實現(xiàn)中文文本關鍵詞抽取的三種方法的詳細內容,更多關于Python關鍵詞抽取的資料請關注腳本之家其它相關文章!
相關文章
python中tf.boolean_mask()函數(shù)的使用方法詳解
這篇文章主要介紹了python中tf.boolean_mask()函數(shù)的使用方法詳解,?tf.boolean_mask()?函數(shù)的作用是通過布爾值對指定的列的元素進行過濾,需要的朋友可以參考下2023-11-11
python機器學習樸素貝葉斯算法及模型的選擇和調優(yōu)詳解
這篇文章主要為大家介紹了python機器學習樸素貝葉斯及模型的選擇和調優(yōu)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2021-11-11
使用Pytest.main()運行時參數(shù)不生效問題解決
本文主要介紹了使用Pytest.main()運行時參數(shù)不生效問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-02-02
tensorflow使用range_input_producer多線程讀取數(shù)據(jù)實例
今天小編就為大家分享一篇tensorflow使用range_input_producer多線程讀取數(shù)據(jù)實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01

