如何用Python提取中文關鍵詞?

王樹義發表於2018-06-28

本文一步步為你演示,如何用Python從中文文字中提取關鍵詞。如果你需要對長文“觀其大略”,不妨嘗試一下。

2017-12-07-20-38-22-7-426487.png

需求

好友最近對自然語言處理感興趣,因為他打算利用自動化方法從長文字里提取關鍵詞,來確定主題。

他向我詢問方法,我推薦他閱讀我的那篇《如何用Python從海量文字提取主題?》。

看過之後,他表示很有收穫,但是應用場景和他自己的需求有些區別

如何用Python從海量文字提取主題?》一文面對的是大量的文件,利用主題發現功能對文章聚類。而他不需要處理很多的文件,也沒有聚類的需求,但是需要處理的每篇文件都很長,希望通過自動化方法從長文提取關鍵詞,以觀其大略。

我突然發現,之前居然忘了寫文,介紹單一文字關鍵詞的提取方法。

雖然這個功能實現起來並不複雜,但是其中也有些坑,需要避免踩進去的。

通過本文,我一步步為你演示如何用Python實現中文關鍵詞提取這一功能。

環境

Python

第一步是安裝Python執行環境。我們使用整合環境Anaconda。

請到這個網址 下載最新版的Anaconda。下拉頁面,找到下載位置。根據你目前使用的系統,網站會自動推薦給你適合的版本下載。我使用的是macOS,下載檔案格式為pkg。

2017-12-03-22-19-31-2-856072.png

下載頁面區左側是Python 3.6版,右側是2.7版。請選擇2.7版本。

雙擊下載後的pkg檔案,根據中文提示一步步安裝即可。

2017-12-03-22-19-31-2-856170.jpeg

樣例

我專門為你準備了一個github專案,存放本文的配套原始碼和資料。請從這個地址下載壓縮包檔案,然後解壓。

解壓後的目錄名稱為demo-keyword-extraction-master,樣例目錄包含以下內容:

2017-12-7_21-24-56_snapshots-01.jpg

除了README.md這個github專案預設說明檔案外,目錄下還有兩個檔案,分別是資料檔案sample.txt和程式原始碼檔案demo-extract-keyword.ipynb。

結巴分詞

我們使用的關鍵詞提取工具為結巴分詞

之前在《如何用Python做中文分詞?》一文中,我們曾經使用過該工具為中文語句做分詞。這次我們使用的,是它的另一項功能,即關鍵詞提取。

請進入終端,使用cd命令進入解壓後的資料夾demo-keyword-extraction-master,輸入以下命令:

pip install jieba
複製程式碼

好了,軟體包工具也已經準備就緒。下面我們執行

jupyter notebook
複製程式碼

進入到Jupyter筆記本環境。

image.png

到這裡,環境已經準備好了,我們下面來介紹本文使用的中文文字資料。

資料

一開始,我還曾為尋找現成的中文文字發愁。

網上可以找到的中文文字浩如煙海。

但是拿來做演示,是否會有版權問題,我就不確定了。萬一把哪位大家之作拿來做了分析,人家可能就要過問一句“這電子版你是從哪裡搞到的啊?”

萬一再因此提出訴訟,我可無法招架。

後來發現,我這簡直就是自尋煩惱——找別人的文字幹什麼?用我自己的不就好了?

這一年多以來,我寫的文章已有90多篇,總字數已經超過了27萬。

image.png

我特意從中找了一篇非技術性的,以避擴音取出的關鍵詞全都是Python命令。

我選取的,是去年的那篇《網約車司機二三事》。

image.png

這篇文章,講的都是些比較有趣的小故事。

我從網頁上摘取文字,儲存到sample.txt中。

注意,這裡是很容易踩坑的地方。在夏天的一次工作坊教學中,好幾位同學因為從網上摘取中文文字出現問題,卡住很長時間。

這是因為不同於英語,漢字有編碼問題。不同系統都有不同的預設編碼,不同版本的Python接受的編碼也不同。你從網上下載的文字檔案,也可能與你係統的編碼不統一。

image.png

不論如何,這些因素都有可能導致你開啟後的文字里,到處都是看不懂的亂碼。

因而,正確的使用中文文字資料方式,是你在Jupyter Notebook裡面,新建一個文字檔案。

image.png

然後,會出現以下的空白檔案。

image.png

把你從別處下載的文字,用任意一種能正常顯示的編輯器開啟,然後拷貝全部內容,貼上到這個空白文字檔案中,就能避免編碼錯亂。

避開了這個坑,可以為你節省很多不必要的煩惱嘗試。

好了,知道了這個竅門,下面你就能愉快地進行關鍵詞提取了。

執行

回到Jupyter Notebook的主介面,點選demo-extract-keyword.ipynb,你就能看到原始碼了。

image.png

對,你沒看錯。只需要這短短的4個語句,就能完成兩種不同方式(TF-idf與TextRank)的關鍵詞提取。

本部分我們先講解執行步驟。不同關鍵詞提取方法的原理,我們放在後面介紹。

首先我們從結巴分詞的分析工具箱裡匯入所有的關鍵詞提取功能。

from jieba.analyse import *
複製程式碼

在對應的語句上,按下Shift+Enter組合按鍵,就可以執行語句,獲取結果了。

然後,讓Python開啟我們的樣例文字檔案,並且讀入其中的全部內容到data變數。

with open('sample.txt') as f:
    data = f.read()
複製程式碼

使用TF-idf方式提取關鍵詞和權重,並且依次顯示出來。如果你不做特殊指定的話,預設顯示數量為20個關鍵詞。

for keyword, weight in extract_tags(data, withWeight=True):
    print('%s %s' % (keyword, weight))
複製程式碼

顯示內容之前,會有一些提示,不要管它。

Building prefix dict from the default dictionary ...
Loading model from cache /var/folders/8s/k8yr4zy52q1dh107gjx280mw0000gn/T/jieba.cache
Loading model cost 0.547 seconds.
Prefix dict has been built succesfully.
複製程式碼

然後列表就出來了:

優步 0.280875594782
司機 0.119951947597
乘客 0.105486129485
師傅 0.0958888107815
張師傅 0.0838162334963
目的地 0.0753618512886
網約車 0.0702188986954
姐姐 0.0683412127766
自己 0.0672533110661
上車 0.0623276916308
活兒 0.0600134354214
天津 0.0569158056792
10 0.0526641740216
開優步 0.0526641740216
事兒 0.048554456767
李師傅 0.0485035501943
天津人 0.0482653686026
繞路 0.0478244723097
計程車 0.0448480260748
時候 0.0440840298591
複製程式碼

我看了一下,覺得關鍵詞提取還是比較靠譜的。當然,其中也混入了個數字10,好在無傷大雅。

如果你需要修改關鍵詞數量,就需要指定topK引數。例如你要輸出10個關鍵詞,可以這樣執行:

for keyword, weight in extract_tags(data, topK=10, withWeight=True):
    print('%s %s' % (keyword, weight))
複製程式碼

下面我們嘗試另一種關鍵詞提取方式——TextRank。

for keyword, weight in textrank(data, withWeight=True):
    print('%s %s' % (keyword, weight))
複製程式碼

關鍵詞提取結果如下:

優步 1.0
司機 0.749405996648
乘客 0.594284506457
姐姐 0.485458741991
天津 0.451113490366
目的地 0.429410027466
時候 0.418083863303
作者 0.416903838153
沒有 0.357764515052
活兒 0.291371566494
上車 0.277010013884
繞路 0.274608592084
轉載 0.271932903186
出來 0.242580745393
出租 0.238639889991
事兒 0.228700322713
單數 0.213450680366
計程車 0.212049665481
拉門 0.205816713637
跟著 0.20513470986
複製程式碼

注意這次提取的結果,與TF-idf的結果有區別。至少,那個很突兀的“10”不見了。

但是,這是不是意味著TextRank方法一定優於TF-idf呢?

這個問題,留作思考題,希望在你認真閱讀了後面的原理部分之後,能夠獨立做出解答。

如果你只需要應用本方法解決實際問題,那麼請跳過原理部分,直接看討論吧。

原理

我們簡要講解一下,前文出現的2種不同關鍵詞提取方式——TF-idf和TextRank的基本原理。

為了不讓大家感到枯燥,這裡我們們就不使用數學公式了。後文我會給出相關的資料連結。如果你對細節感興趣,歡迎按圖索驥,查閱學習。

先說TF-idf。

它的全稱是 Term Frequency - inverse document frequency。中間有個連字元,左右兩側各是一部分,共同結合起來,決定某個詞的重要程度。

第一部分,就是詞頻(Term Frequency),即某個詞語出現的頻率。

我們常說“重要的事說三遍”。

同樣的道理,某個詞語出現的次數多,也就說明這個詞語重要性可能會很高。

但是,這只是可能性,並不絕對。

例如現代漢語中的許多虛詞——“的,地,得”,古漢語中的許多句尾詞“之、乎、者、也、兮”,這些詞在文中可能出現許多次,但是它們顯然不是關鍵詞。

這就是為什麼我們在判斷關鍵詞的時候,需要第二部分(idf)配合。

逆文件頻率(inverse document frequency)首先計算某個詞在各文件中出現的頻率。假設一共有10篇文件,其中某個詞A在其中10篇文章中都出先過,另一個詞B只在其中3篇文中出現。請問哪一個詞更關鍵?

給你一分鐘思考一下,然後繼續讀。

公佈答案時間到。

答案是B更關鍵。

A可能就是虛詞,或者全部文件共享的主題詞。而B只在3篇文件中出現,因此很有可能是個關鍵詞。

逆文件頻率就是把這種文件頻率取倒數。這樣第一部分和第二部分都是越高越好。二者都高,就很有可能是關鍵詞了。

TF-idf講完了,下面我們說說TextRank。

相對於TF-idf,TextRank要顯得更加複雜一些。它不是簡單做加減乘除運算,而是基於圖的計算。

下圖是原始文獻中的示例圖。

image.png

TextRank首先會提取詞彙,形成節點;然後依據詞彙的關聯,建立連結。

依照連線節點的多少,給每個節點賦予一個初始的權重數值。

然後就開始迭代。

根據某個詞所連線所有詞彙的權重,重新計算該詞彙的權重,然後把重新計算的權重傳遞下去。直到這種變化達到均衡態,權重數值不再發生改變。這與Google的網頁排名演算法PageRank,在思想上是一致的。

image.png

根據最後的權重值,取其中排列靠前的詞彙,作為關鍵詞提取結果。

如果你對原始文獻感興趣,請參考以下連結:

討論

小結一下,本文探討了如何用Python對中文文字做關鍵詞提取。具體而言,我們分別使用了TF-idf和TextRank方法,二者提取關鍵詞的結果可能會有區別。

你做過中文關鍵詞提取嗎?使用的是什麼工具?它的效果如何?有沒有比本文更高效的方法?歡迎留言,把你的經驗和思考分享給大家,我們一起交流討論。

喜歡請點贊。還可以微信關注和置頂我的公眾號“玉樹芝蘭”(nkwangshuyi)

如果你對資料科學感興趣,不妨閱讀我的系列教程索引貼《如何高效入門資料科學?》,裡面還有更多的有趣問題及解法。

相關文章