前言
關鍵詞提取就是從文本里面把跟這篇文章意義最相關的一些詞語抽取出來。這個可以追溯到文獻檢索初期,關鍵詞是為了文獻標引工作,從報告、論文中選取出來用以表示全文主題內容信息的單詞或術語,在現在的報告和論文中,我們依然可以看到關鍵詞這一項。因此,關鍵詞在文獻檢索、自動文摘、文本聚類/分類等方面有着重要的應用,它不僅是進行這些工作不可或缺的基礎和前提,也是互聯網上信息建庫的一項重要工作。
關鍵詞抽取從方法來說主要有兩種:
- 第一種是關鍵詞分配:就是給定一個已有的關鍵詞庫,對於新來的文檔從該詞庫里面匹配幾個詞語作為這篇文檔的關鍵詞。
- 第二種是關鍵詞提取:針對新文檔,通過算法分析,提取文檔中一些詞語作為該文檔的關鍵詞。
目前大多數應用領域的關鍵詞抽取算法都是基於后者實現的,從邏輯上說,后者比前者在實際應用中更准確。
下面介紹一些關於關鍵詞抽取的常用和經典的算法實現。
基於 TF-IDF 算法進行關鍵詞提取
在信息檢索理論中,TF-IDF 是 Term Frequency - Inverse Document Frequency 的簡寫。TF-IDF 是一種數值統計,用於反映一個詞對於語料中某篇文檔的重要性。在信息檢索和文本挖掘領域,它經常用於因子加權。TF-IDF 的主要思想就是:如果某個詞在一篇文檔中出現的頻率高,也即 TF 高;並且在語料庫中其他文檔中很少出現,即 DF 低,也即 IDF 高,則認為這個詞具有很好的類別區分能力。
TF 為詞頻(Term Frequency),表示詞 t 在文檔 d 中出現的頻率,計算公式:
其中,ni,j 是該詞 ti 在文件 dj 中的出現次數,而分母則是在文件 dj 中所有字詞的出現次數之和。
IDF 為逆文檔頻率(Inverse Document Frequency),表示語料庫中包含詞 t 的文檔的數目的倒數,計算公式:
其中,|D|
表示語料庫中的文件總數,|{j:ti∈dj}| 包含詞 ti 的文件數目,如果該詞語不在語料庫中,就會導致被除數為零,因此一般情況下使用 1+|{j:ti∈dj}|。
TF-IDF 在實際中主要是將二者相乘,也即 TF * IDF, 計算公式:
因此,TF-IDF 傾向於過濾掉常見的詞語,保留重要的詞語。例如,某一特定文件內的高頻率詞語,以及該詞語在整個文件集合中的低文件頻率,可以產生出高權重的 TF-IDF。
好在 jieba 已經實現了基於 TF-IDF 算法的關鍵詞抽取,通過命令 import jieba.analyse
引入,函數參數解釋如下:
- sentence:待提取的文本語料;
- topK:返回 TF/IDF 權重最大的關鍵詞個數,默認值為 20;
- withWeight:是否需要返回關鍵詞權重值,默認值為 False;
- allowPOS:僅包括指定詞性的詞,默認值為空,即不篩選。
接下來看例子,我采用的語料來自於百度百科對人工智能的定義,獲取 Top20 關鍵字,用空格隔開打印:
import jieba.analyse
sentence = "人工智能(Artificial Intelligence),英文縮寫為AI。它是研究、開發用於模擬、延伸和擴展人的智能的理論、方法、技術及應用系統的一門新的技術科學。人工智能是計算機科學的一個分支,它企圖了解智能的實質,並生產出一種新的能以人類智能相似的方式做出反應的智能機器,該領域的研究包括機器人、語言識別、圖像識別、自然語言處理和專家系統等。人工智能從誕生以來,理論和技術日益成熟,應用領域也不斷擴大,可以設想,未來人工智能帶來的科技產品,將會是人類智慧的“容器”。人工智能可以對人的意識、思維的信息過程的模擬。人工智能不是人的智能,但能像人那樣思考、也可能超過人的智能。人工智能是一門極富挑戰性的科學,從事這項工作的人必須懂得計算機知識,心理學和哲學。人工智能是包括十分廣泛的科學,它由不同的領域組成,如機器學習,計算機視覺等等,總的說來,人工智能研究的一個主要目標是使機器能夠勝任一些通常需要人類智能才能完成的復雜工作。但不同的時代、不同的人對這種“復雜工作”的理解是不同的。2017年12月,人工智能入選“2017年度中國媒體十大流行語”。"
keywords = " ".join(jieba.analyse.extract_tags(sentence , topK=20, withWeight=False, allowPOS=()))
print(keywords)
執行結果:
人工智能 智能 2017 機器 不同 人類 科學 模擬 一門 技術 計算機 研究 工作 Artificial Intelligence AI 圖像識別 12 復雜 流行語
下面只獲取 Top10 的關鍵字,並修改一下詞性,只選擇名詞和動詞,看看結果有何不同?
keywords =(jieba.analyse.extract_tags(sentence , topK=10, withWeight=True, allowPOS=(['n','v'])))
print(keywords)
執行結果:
[('人工智能', 0.9750542675762887), ('智能', 0.5167124540885567), ('機器', 0.20540911929525774), ('人類', 0.17414426566082475), ('科學', 0.17250169374402063), ('模擬', 0.15723537382948452), ('技術', 0.14596259315164947), ('計算機', 0.14030483362639176), ('圖像識別', 0.12324502580309278), ('流行語', 0.11242211730309279)]
基於 TextRank 算法進行關鍵詞提取
TextRank 是由 PageRank 改進而來,核心思想將文本中的詞看作圖中的節點,通過邊相互連接,不同的節點會有不同的權重,權重高的節點可以作為關鍵詞。這里給出 TextRank 的公式:
節點 i 的權重取決於節點 i 的鄰居節點中 i-j 這條邊的權重 / j 的所有出度的邊的權重 * 節點 j 的權重,將這些鄰居節點計算的權重相加,再乘上一定的阻尼系數,就是節點 i 的權重,阻尼系數 d 一般取 0.85。
TextRank 用於關鍵詞提取的算法如下:
(1)把給定的文本 T 按照完整句子進行分割,即:
(2)對於每個句子,進行分詞和詞性標注處理,並過濾掉停用詞,只保留指定詞性的單詞,如名詞、動詞、形容詞,其中 ti,j 是保留后的候選關鍵詞。
(3)構建候選關鍵詞圖 G = (V,E),其中 V 為節點集,由(2)生成的候選關鍵詞組成,然后采用共現關系(Co-Occurrence)構造任兩點之間的邊,兩個節點之間存在邊僅當它們對應的詞匯在長度為 K 的窗口中共現,K 表示窗口大小,即最多共現 K 個單詞。
(4)根據 TextRank 的公式,迭代傳播各節點的權重,直至收斂。
(5)對節點權重進行倒序排序,從而得到最重要的 T 個單詞,作為候選關鍵詞。
(6)由(5)得到最重要的 T 個單詞,在原始文本中進行標記,若形成相鄰詞組,則組合成多詞關鍵詞。
同樣 jieba 已經實現了基於 TextRank 算法的關鍵詞抽取,通過命令 import jieba.analyse
引用,函數參數解釋如下:
jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))
直接使用,接口參數同 TF-IDF 相同,注意默認過濾詞性。
接下來,我們繼續看例子,語料繼續使用上例中的句子。
result = " ".join(jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v')))
print(result)
執行結果:
智能 人工智能 機器 人類 研究 技術 模擬 包括 科學 工作 領域 理論 計算機 年度 需要 語言 相似 方式 做出 心理學
如果修改一下詞性,只需要名詞和動詞,看看結果有何不同?
result = " ".join(jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('n','v')))
print(result)
執行結果:
智能 人工智能 機器 人類 技術 模擬 包括 科學 理論 計算機 領域 年度 需要 心理學 信息 語言 識別 帶來 過程 延伸
基於 LDA 主題模型進行關鍵詞提取
語料是一個關於汽車的短文本,下面通過 Gensim 庫完成基於 LDA 的關鍵字提取。整個過程的步驟為:文件加載 -> jieba 分詞 -> 去停用詞 -> 構建詞袋模型 -> LDA 模型訓練 -> 結果可視化。
#引入庫文件
import jieba.analyse as analyse
import jieba
import pandas as pd
from gensim import corpora, models, similarities
import gensim
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
#設置文件路徑
dir = "/Users/jianliu/Downloads/"
file_desc = "".join([dir,'car.csv'])
stop_words = "".join([dir,'stopwords.txt'])
#定義停用詞
stopwords=pd.read_csv(stop_words,index_col=False,quoting=3,sep="\t",names=['stopword'], encoding='utf-8')
stopwords=stopwords['stopword'].values
#加載語料
df = pd.read_csv(file_desc, encoding='gbk')
#刪除nan行
df.dropna(inplace=True)
lines=df.content.values.tolist()
#開始分詞
sentences=[]
for line in lines:
try:
segs=jieba.lcut(line)
segs = [v for v in segs if not str(v).isdigit()]#去數字
segs = list(filter(lambda x:x.strip(), segs)) #去左右空格
segs = list(filter(lambda x:x not in stopwords, segs)) #去掉停用詞
sentences.append(segs)
except Exception:
print(line)
continue
#構建詞袋模型
dictionary = corpora.Dictionary(sentences)
corpus = [dictionary.doc2bow(sentence) for sentence in sentences]
#lda模型,num_topics是主題的個數,這里定義了5個
lda = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=10)
#我們查一下第1號分類,其中最常出現的5個詞是:
print(lda.print_topic(1, topn=5))
#我們打印所有5個主題,每個主題顯示8個詞
for topic in lda.print_topics(num_topics=10, num_words=8):
print(topic[1])
執行結果如下圖所示:
#顯示中文matplotlib
plt.rcParams['font.sans-serif'] = [u'SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 在可視化部分,我們首先畫出了九個主題的7個詞的概率分布圖
num_show_term = 8 # 每個主題下顯示幾個詞
num_topics = 10
for i, k in enumerate(range(num_topics)):
ax = plt.subplot(2, 5, I+1)
item_dis_all = lda.get_topic_terms(topicid=k)
item_dis = np.array(item_dis_all[:num_show_term])
ax.plot(range(num_show_term), item_dis[:, 1], 'b*')
item_word_id = item_dis[:, 0].astype(np.int)
word = [dictionary.id2token[i] for i in item_word_id]
ax.set_ylabel(u"概率")
for j in range(num_show_term):
ax.text(j, item_dis[j, 1], word[j], bbox=dict(facecolor='green',alpha=0.1))
plt.suptitle(u'9個主題及其7個主要詞的概率', fontsize=18)
plt.show()
執行結果如下圖所示:
基於 pyhanlp 進行關鍵詞提取
除了 jieba,也可以選擇使用 HanLP 來完成關鍵字提取,內部采用 TextRankKeyword 實現,語料繼續使用上例中的句子。
from pyhanlp import *
result = HanLP.extractKeyword(sentence, 20)
print(result)
執行結果:
[人工智能, 智能, 領域, 人類, 研究, 不同, 工作, 包括, 模擬, 新的, 機器, 計算機, 門, 科學, 應用, 系統, 理論, 技術, 入選, 復雜]
總結
本節內容的重點就是掌握關鍵字提取的基本方法,常規的關鍵詞提取方法如上所述,當然還有其他算法及其改進,有深入研究需求的,可以下載關鍵字提取方面的論文閱讀。