基於 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模塊是爲了顯示詞雲圖
運行文件,得到結果如下圖所示:
從結果圖可以看出,在衆多魅力各異的角色中,侯亮平和李達康是《人民的名義》中登場率最高的人物,祁同偉、高育良等人的存在感也不相上下。看來,達康書記在網絡上的超高人氣不是空穴來風啊!