基于 jieba 和 word_cloud 生成《人民的名義》小說詞雲
由于詞雲在反映文本關鍵資訊上的顯著優勢,在本文中,我選擇結合執行個體為大家介紹一下 Python 中專門用來生成詞雲的一個庫——word_cloud 。
執行個體中的分析對象就選擇為最近大火的電視劇《人民的名義》小說原著,通過詞雲來分析一下小說各具魅力的人物中,究竟誰的出場率最高,誰是真正的主角。
考慮到 Word_Cloud 的預設處理對象是英文,對中文的分詞效果不夠理想,是以在執行個體中還用到了一個強大的中文分詞元件——jieba ,在文章中也會給大家進行簡單介紹。
一、準備工作
1.1 word_cloud 介紹
首先,為大家介紹一下 word_cloud 庫的基本資訊。word_cloud 是哥倫比亞大學的Andreas Müller 開發的基于 Python 的詞雲生成器,同時支援Python2 和 Python3 。 word_cloud 使用的詞雲生成算法簡潔高效,支援任意形狀的圖檔模闆,可以自動生成配色。也可以對詞雲中單詞的數量、配色、尺寸、排列方式等一系列參數進行自定義的設定。
在word_cloud 庫裡,最重要的一個類是 WordCloud 。這個類中的屬性包含了詞雲生成過程中的各項相關參數,方法中則包含了文本分詞、詞雲的生成、繪制等一系列函數。首先,我們來看一下 WordCLoud 的屬性:
class wordcloud.WordCloud(font_path=None, width=400, height=200, margin=2, ranks_only=None, prefer_horizontal=0.9, mask=None, scale=1, color_func=None, max_words=200, min_font_size=4, stopwords=None, random_state=None, background_color='black', max_font_size=None, font_step=1, mode='RGB', relative_scaling=0.5, regexp=None, collocations=True, colormap=None, normalize_plurals=True)
可以看到,WordCloud這個函數有22個參數,能夠設定詞雲生成過程中各個方面的參數,我們可以通過設定這些參數的取值來實作我們想要的效果。當然,這麼多參數,我們隻需要設定我們最關心的幾個參數,其餘參數取預設值就可以了。這裡,簡單介紹一下我們将要用到的幾個重要參數:
- 第一個參數是 font_path,字型路徑。這個參數用來選擇生成詞雲中文字使用的字型。在Linux環境中,字型預設的是DroidSansMono,如果沒有這個字型或者使用的是其他作業系統,都需要下載下傳字型檔案,對這個參數賦予字型所在路徑。需要注意的是,由于預設字型是英文字型,我們在進行中文文本時,建議使用自己選擇的漢字字型。在選擇字型的過程中,最好選擇字庫比較完整的經典字型,如黑體、宋體等字型。若使用一些字庫不夠完整的特殊字型,容易出現詞雲中一些漢字無法顯示的情況,影響效果。
- 第二個參數是 mask ,模闆圖檔。這個參數用來選擇詞雲生成形狀的模闆。預設不設定情況下,生成詞雲會是一個矩形。選作模闆的圖檔需要是一副二值圖像。模闆圖像矩陣中,白色(#FF 或 #FFFFFF) 的元素位置會被排除,其餘的元素位置會被單詞填滿。也就是說,使用一副黑白圖像作為模闆時,生成的詞雲是黑色部分的形狀。輸入的模闆圖檔的格式支援常用格式如png、jpeg等。
- 第三個參數是 max_words,最大單詞數。顧名思義,這個參數決定了詞雲中顯示的單詞的總數上限,我們可以根據具體應用需求來設定這個參數的大小。類似的還有max_font_size(最大字型尺寸)、min_font_size(最小字型尺寸)、backgroud_color(背景顔色)等一系列功能明确的參數,可以根據需要自由設定,沒有特殊的限制。
關于 WordCloud 類的屬性,以上的介紹已經可以滿足我們的基本使用需要,接下來我們來了解一下 WordCloud 類中的主要方法。WordCloud 類中包含的方法如下所示:
方法 | 簡介 |
---|---|
fit_words(frequencies) | Create a word_cloud from words and frequencies |
generate(text) | Generate wordcloud from text |
generate_from_frequencies(frequencies[, …]) | Create a word_cloud from words and frequencies |
generate_from_text(text) | Generate wordcloud from text |
process_text(text) | Splits a long text into words, eliminates the stopwords |
recolor([random_state, color_func, colormap]) | Recolor existing layout |
to_array() | Convert to numpy array |
to_file(filename) | Export to image file |
to_html() | Export to html file |
to_image() | Export to image |
在這些方法函數中,本篇将會用到的函數主要是從文本中生成詞雲的函數 generate(text) 。函數的輸入是txt格式的文本檔案,輸出最終的詞雲資料。這裡需要注意的是,函數輸入的文本檔案對内容格式是有要求的。文本必須由一個個獨立分隔開的詞語構成,這樣函數才可以對每個詞語的出現頻率進行統計,生成詞雲。
在本篇的執行個體中,我們處理的對象是《人民的名義》小說文本,文本全部由句子構成,不能直接作為 generate 函數的輸入值。是以,我們需要對由句子構成的文本進行”分詞“的預處理。顧名思義,分詞就是将句子分解成若幹個獨立的詞彙。在上表中可以看到,WordCloud 類中提供了實作分詞功能的函數 process_text(text)。但是這個函數的設計是主要面向英文文本的分詞的,是以對中文的分詞效果不能令人滿意。
為了解決分詞的問題,本篇選擇了中文分詞工具庫 jieba,下面就介紹一下jieba 相關的基本知識。
1.2 Jieba 介紹
Jieba,也就是“結巴”中文分詞,是一個非常強大且完善的中文分詞元件。Jieba 庫有很多語言的實作版本, Python 版本同時支援 Python2 和 Python3。
Jieba的主要功能特性有以下幾點:
- 支援三種分詞模式:
- 精确模式,試圖将句子最精确地切開,适合文本分析;
- 全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非常快,但是不能解決歧義;
- 搜尋引擎模式,在精确模式的基礎上,對長詞再次切分,提高召回率,适合用于搜尋引擎分詞。
- 支援繁體分詞
- 支援自定義詞典
- MIT 授權協定
Jieba能夠實作分詞、添加自定義詞典、關鍵詞提取、詞性标注、并行分詞、Tokenize傳回詞語在原文的起止位置、ChineseAnalyzer for Whoosh 搜尋引擎、指令行分詞等一系列非常豐富功能。在本篇當中,我們主要會用到分詞、添加自定義詞典和關鍵詞提取的功能,下面分别介紹一下這三個功能的基本實作。
1.2.1 分詞功能
- jieba.cut 方法接受三個輸入參數: 需要分詞的字元串;cut_all 參數用來控制是否采用全模式;HMM 參數用來控制是否使用 HMM 模型
- jieba.cut_for_search 方法接受兩個參數:需要分詞的字元串;是否使用 HMM 模型。該方法适合用于搜尋引擎建構反向索引的分詞,粒度比較細
- 待分詞的字元串可以是 unicode 或 UTF-8 字元串、GBK 字元串。注意:不建議直接輸入 GBK 字元串,可能無法預料地錯誤解碼成 UTF-8
- jieba.cut 以及 jieba.cut_for_search 傳回的結構都是一個可疊代的 generator,可以使用 for 循環來獲得分詞後得到的每一個詞語(unicode),或者用jieba.lcut 以及 jieba.lcut_for_search 直接傳回 list
- jieba.Tokenizer(dictionary=DEFAULT_DICT) 建立自定義分詞器,可用于同時使用不同詞典。jieba.dt 為預設分詞器,所有全局分詞相關函數都是該分詞器的映射。
代碼示例
# encoding=utf-8
import jieba
seg_list = jieba.cut("我來到北京清華大學", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我來到北京清華大學", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
seg_list = jieba.cut("他來到了網易杭研大廈") # 預設是精确模式
print(", ".join(seg_list))
seg_list = jieba.cut_for_search("小明碩士畢業于中國科學院計算所,後在日本京都大學深造") # 搜尋引擎模式
print(", ".join(seg_list))
Building prefix dict from the default dictionary ...
Loading model from cache /tmp/jieba.cache
Loading model cost 1.059 seconds.
Prefix dict has been built succesfully.
Full Mode: 我/ 來到/ 北京/ 清華/ 清華大學/ 華大/ 大學
Default Mode: 我/ 來到/ 北京/ 清華大學
他, 來到, 了, 網易, 杭研, 大廈
小明, 碩士, 畢業, 于, 中國, 科學, 學院, 科學院, 中國科學院, 計算, 計算所, ,, 後, 在, 日本, 京都, 大學, 日本京都大學, 深造
1.2.2 添加自定義詞典功能
- 開發者可以指定自己自定義的詞典,以便包含 jieba 詞庫裡沒有的詞。雖然 jieba 有新詞識别能力,但是自行添加新詞可以保證更高的正确率
- 用法: jieba.load_userdict(file_name) # file_name 為檔案類對象或自定義詞典的路徑
- 詞典格式和 dict.txt 一樣,一個詞占一行;每一行分三部分:詞語、詞頻(可省略)、詞性(可省略),用空格隔開,順序不可颠倒。file_name 若為路徑或二進制方式打開的檔案,則檔案必須為 UTF-8 編碼。
- 詞頻省略時使用自動計算的能保證分出該詞的詞頻。
1.3.3 關鍵詞提取功能
基于 TF-IDF 算法的關鍵詞抽取
import jieba.analyse
- jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
- sentence 為待提取的文本
- topK 為傳回幾個 TF/IDF 權重最大的關鍵詞,預設值為 20
- withWeight 為是否一并傳回關鍵詞權重值,預設值為 False
- allowPOS 僅包括指定詞性的詞,預設值為空,即不篩選
- jieba.analyse.TFIDF(idf_path=None) 建立 TFIDF 執行個體,idf_path 為 IDF 頻率檔案
基于 TextRank 算法的關鍵詞抽取
- jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=(‘ns’, ‘n’, ‘vn’, ‘v’)) 直接使用,接口相同,注意預設過濾詞性。
- jieba.analyse.TextRank() 建立自定義 TextRank 執行個體
1.3 環境搭建
在對 word_cloud 和 jieba 兩個庫有了基本的了解之後,我們來學習一下兩個庫的安裝和相關環境的搭建。
1.3.1 word_cloud 的安裝
- 快速安裝(使用pip指令):
pip install wordcloud
- 使用anaconda安裝:
conda install -c https://conda.anaconda.org/amueller wordcloud
- 手動安裝-軟體包擷取:
wget https://github.com/amueller/word_cloud/archive/master.zip
unzip master.zip
rm master.zip
cd word_cloud-master
- 軟體包安裝:
python setup.py install
1.3.2 jieba 的安裝
- 全自動安裝:easy_install jieba 或者 pip install jieba / pip3 install jieba
- 半自動安裝:先下載下傳 http://pypi.python.org/pypi/jieba/ ,解壓後運作 python setup.py install
- 手動安裝:将 jieba 目錄放置于目前目錄或者 site-packages 目錄
- 通過 import jieba 來引用
1.3.3 Anaconda 的使用
個人在這裡推薦使用 Anaconda 來配置 Python 開發環境。
Anaconda是專注于資料分析的Python發行版本,包含了conda、Python等190多個科學包及其依賴項。而conda 是開源包(packages)和虛拟環境(environment)的管理系統。
- packages 管理: 可以使用 conda 來安裝、更新 、解除安裝工具包 ,并且它更關注于資料科學相關的工具包。在安裝 anaconda 時就預先內建了像 Numpy、Scipy、 pandas、Scikit-learn 這些在資料分析中常用的包。另外值得一提的是,conda 并不僅僅管理Python的工具包,它也能安裝非python的包。比如在新版的 Anaconda 中就可以安裝R語言的內建開發環境 Rstudio。
- 虛拟環境管理: 在conda中可以建立多個虛拟環境,用于隔離不同項目所需的不同版本的工具包,以防止版本上的沖突。對糾結于 Python 版本的同學們,我們也可以建立 Python2 和 Python3 兩個環境,來分别運作不同版本的 Python 代碼。
Anaconda通過管理工具包、開發環境、Python版本,大大簡化了工作流程。不僅可以友善地安裝、更新、解除安裝工具包,而且安裝時能自動安裝相應的依賴包,同時還能使用不同的虛拟環境隔離不同要求的項目。
如果想要安裝Anaconda的話,可以通過官網下載下傳頁面下載下傳 Anaconda 的安裝程式以及檢視安裝說明,在這裡就不再贅述了。
1.4 實作思路
在完成基礎知識了解和環境配置後,我們可以來思考一下具體的實作過程了。
我們的目标是生成《人民的名義》小說詞雲,我們希望詞雲中的詞彙隻有角色的名字,沒有其他無關詞彙,這樣才能更好地反映出角色的比重。
我們的處理對象是從網絡獲得的《人民的名義》小說 txt 檔案,編碼格式為 utf-8 ,字元數為268375。
根據之前的基礎知識,我們不難獲得整個程式的實作思路:
- 分詞
- 小說文本整體分詞
- 建構自定義人名詞典
- 篩選關鍵詞
- 生成詞雲,繪制圖檔
是以,我們隻需要設計兩個函數。第一個函數是分詞函數,用來實作小說的整體分詞和人名篩選等功能,獲得隻包含人名的分詞結果。第二個函數就是詞雲生成函數,使用分詞函數的分詞結果作為輸入,對詞雲的模闆、詞量等參數進行設定,輸出最終的詞雲結果,并儲存為圖檔檔案。
二、程式設計
2.1 庫的導入
首先,程式的開始我們要聲明編碼方式,并導入需要用到的庫檔案,代碼如下:
#-*- coding:utf-8 -*-
#encoding=utf8
import codecs
import jieba
jieba.load_userdict("namedict.txt")
import jieba.analyse as analyse
from wordcloud import WordCloud
from scipy.misc import imread
from os import path
可以看到,我們引入了 codecs,是為了使用 codecs.open() 函數打開文本檔案,引用了jieba.analyse 是為了調用其中的 extract_tags 函數來實作關鍵詞的篩選。值得注意的是,在這裡,我加載了自定義字典檔案 “namedict.txt”。在這個字典檔案中,依照溫暖的文檔要求的格式,記錄了21個小說中人物角色的姓名,并标注詞性為”nr“,代表名字。下面是部分示例。
侯亮平 nr
沙瑞金 nr
祁同偉 nr
李達康 nr
高育良 nr
通過這個自定義詞典的加載,我們可以保證分詞過程中,角色名字可以正确完整地被分割出來,并且可以根據詞性”nr“,将所有名字篩選出來。
2.2 分詞函數的實作
代碼如下,代碼的原理在注釋中有詳細介紹:
def seg_sentence(file_name):
with codecs.open(file_name,encoding='utf-8') as f: #打開檔案
original_text = f.read() #讀取檔案内容為字元original_text
wordList = jieba.cut(original_text) #全文分詞,結果存儲在wordlist中
print('全文分詞完成...')
allow_pos = ('nr',) #設定篩選參數為”nr“,名字
tags = jieba.analyse.extract_tags(original_text, topK=30, withWeight=False, allowPOS=allow_pos)
#從原文文本original_text中,篩選詞性為”nr“的前30個詞彙作為關鍵詞
print('關鍵詞篩選完成...')
stags=" ".join(tags) #将關鍵詞通過空格連接配接為字元串stags
f2=open(u"stags.txt","w+")
f2.write(stags)
f2.write("\n")
f2.close() #将獲得的關鍵詞存儲到stags.txt檔案中(供調試檢視)
outstr = ''
for word in wordList: #周遊全文分詞結果wordlist
if word in stags: #與關鍵詞字元串比較,隻保留關鍵詞
if len(word) > 1: # 去掉長度小于1的詞
if word != '\t':
outstr += word
outstr += " "
#将保留下的詞輸出到字元串outstr中,通過空格連接配接為字元串
return outstr
print ("生産詞雲文本...")
2.3 詞雲生成函數的實作
代碼如下,代碼的原理在注釋中有詳細介紹:
# 繪制詞雲
def draw_wordcloud(file_name):
outstr=seg_sentence(file_name)
#調用分詞函數,生成隻包含關鍵詞的分詞文本outstr,字元串格式
f2=open(u"分詞後.txt","w+")
f2.write(outstr)
f2.write("\n")
f2.close() #将outstr儲存到 分詞後.txt檔案中 (供調試檢視)
font='/home/xplanet/下載下傳/black.ttf'
#選擇字型路徑,這裡使用了黑體
color_mask = imread("/home/xplanet/下載下傳/star.jpeg")
#讀取模闆圖檔,這裡使用了一張五角星圖檔
cloud = WordCloud(font_path=font,background_color='white',mask=color_mask,max_words=100,max_font_size=60)
#設定詞雲參數,字型,模闆,背景白色,最大詞量100個,最大字型尺寸60
word_cloud = cloud.generate(outstr) # 産生詞雲資料 word_cloud
print ("詞雲完成...")
word_cloud.to_file("w_cloud.jpg") #詞雲儲存為圖檔w_cloud.jpg
print ("詞雲儲存成功...")
return word_cloud
2.4 函數的調用
兩個主要函數定義完成後,就可以設定小說文本路徑,直接調用詞雲生成函數生成詞雲了。
這裡需要的代碼也很簡單,如下所示:
file_name = '/home/xplanet/下載下傳/人民的名義2.txt' #設定小說所在路徑
word_cloud=draw_wordcloud(file_name)
#調用詞雲生成函數,生成詞雲word_cloud,并儲存成為圖檔
import matplotlib.pyplot as plt
plt.imshow(word_cloud)
plt.axis("off")
plt.show() #引入matplotlib子產品是為了顯示詞雲圖
三、實踐結果
将上述代碼編寫到一個Python檔案txtwc.py中,如下所示:
# -*- coding:utf-8 -*-
#encoding=utf8
import codecs
import jieba
jieba.load_userdict("namedict.txt")
import jieba.analyse as analyse
from wordcloud import WordCloud
from scipy.misc import imread
from os import path
def seg_sentence(file_name):
with codecs.open(file_name,encoding='utf-8') as f: #打開檔案
original_text = f.read() #讀取檔案内容為字元串original_text
wordList = jieba.cut(original_text) #全文分詞,結果存儲在wordlist中
print('全文分詞完成...')
allow_pos = ('nr',) #設定篩選參數為”nr“,名字
tags = jieba.analyse.extract_tags(original_text, topK=30, withWeight=False, allowPOS=allow_pos)
#從原文文本original_text中,篩選詞性為”nr“的前30個詞彙作為關鍵詞
print('關鍵詞篩選完成...')
stags=" ".join(tags) #将關鍵詞通過空格連接配接為字元串stags
f2=open(u"stags.txt","w+")
f2.write(stags)
f2.write("\n")
f2.close() #将獲得的關鍵詞存儲到stags.txt檔案中(供調試檢視)
outstr = ''
for word in wordList: #周遊全文分詞結果wordlist
if word in stags: #與關鍵詞字元串比較,隻保留關鍵詞
if len(word) > 1: # 去掉長度小于1的詞
if word != '\t':
outstr += word
outstr += " "
#将保留下的詞輸出到字元串outstr中,通過空格連接配接為字元串
return outstr
print ("生産詞雲文本...")
# 繪制詞雲
def draw_wordcloud(file_name):
outstr=seg_sentence(file_name)
#調用分詞函數,生成隻包含關鍵詞的分詞文本outstr,字元串格式
f2=open(u"分詞後.txt","w+")
f2.write(outstr)
f2.write("\n")
f2.close() #将outstr儲存到 分詞後.txt檔案中 (供調試檢視)
font='/home/xplanet/下載下傳/black.ttf' #選擇字型路徑,這裡使用了黑體
color_mask = imread("/home/xplanet/下載下傳/star.jpeg")
#讀取模闆圖檔,這裡使用了一張五角星圖檔
cloud = WordCloud(font_path=font,background_color='white',mask=color_mask,max_words=100,max_font_size=60)
#設定詞雲參數,字型,模闆,背景白色,最大詞量100個,最大字型尺寸60
word_cloud = cloud.generate(outstr) # 産生詞雲資料 word_cloud
print ("詞雲完成...")
word_cloud.to_file("w_cloud.jpg") #詞雲儲存為圖檔w_cloud.jpg
print ("詞雲儲存成功...")
return word_cloud
file_name = '/home/xplanet/下載下傳/人民的名義2.txt' #設定小說所在路徑
word_cloud=draw_wordcloud(file_name)
#調用詞雲生成函數,生成詞雲word_cloud,并儲存成為圖檔
import matplotlib.pyplot as plt
plt.imshow(word_cloud)
plt.axis("off")
plt.show() #引入matplotlib子產品是為了顯示詞雲圖
運作檔案,得到結果如下圖所示:
從結果圖可以看出,在衆多魅力各異的角色中,侯亮平和李達康是《人民的名義》中登場率最高的人物,祁同偉、高育良等人的存在感也不相上下。看來,達康書記在網絡上的超高人氣不是空穴來風啊!