天天看點

基于 jieba 和 word_cloud 生成《人民的名義》小說詞雲

基于 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。

       根據之前的基礎知識,我們不難獲得整個程式的實作思路:

  1. 分詞
    • 小說文本整體分詞
    • 建構自定義人名詞典
    • 篩選關鍵詞
  2. 生成詞雲,繪制圖檔

       是以,我們隻需要設計兩個函數。第一個函數是分詞函數,用來實作小說的整體分詞和人名篩選等功能,獲得隻包含人名的分詞結果。第二個函數就是詞雲生成函數,使用分詞函數的分詞結果作為輸入,對詞雲的模闆、詞量等參數進行設定,輸出最終的詞雲結果,并儲存為圖檔檔案。

二、程式設計

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子產品是為了顯示詞雲圖           

運作檔案,得到結果如下圖所示:

基于 jieba 和 word_cloud 生成《人民的名義》小說詞雲

       從結果圖可以看出,在衆多魅力各異的角色中,侯亮平和李達康是《人民的名義》中登場率最高的人物,祁同偉、高育良等人的存在感也不相上下。看來,達康書記在網絡上的超高人氣不是空穴來風啊!