WordCloud 中英文詞雲圖繪製,看這一篇就夠了
- 2019 年 10 月 8 日
- 筆記

摘要: 當我們手中有一篇文檔,比如書籍、小說、電影劇本,若想快速了解其主要內容是什麼,則可以採用繪製 WordCloud 詞雲圖,顯示主要的關鍵詞(高頻詞)這種方式,非常方便。本文將介紹常見的英文和中文文本的詞雲圖繪製,以及 Frequency 頻詞頻詞雲圖。
寫在前面:由於文中有一些超鏈接,無法在公眾號打開,建議點擊底部「閱讀原文」或者複製下面的博客鏈接到瀏覽器打開,體驗更好。
https://www.makcyun.top/
在上一篇文章「pyspider 爬取並分析虎嗅網 5 萬篇文章 」中的文本可視化部分,我們通過 WordCloud 和 jieba 兩個包繪製了中文詞雲圖,當時只是羅列出了代碼,並沒有詳細介紹。接下來,將詳細說明各種形式的詞雲圖繪製步驟。

1. 英文詞雲
我們先繪製英文文本的詞雲圖,因為它相對簡單一些。這裡以《海上鋼琴師》這部電影的劇本為例。
首先,準備好電影劇本的文本文件(如下圖):

接下來,我們繪製一個最簡單的矩形詞雲圖,代碼如下:
1import os 2from os import path 3from wordcloud import WordCloud 4from matplotlib import pyplot as plt 5# 獲取當前文件路徑 6d = path.dirname(__file__) if "__file__" in locals() else os.getcwd() 7# 獲取文本text 8text = open(path.join(d,'legend1900.txt')).read() 9# 生成詞雲 10wc = WordCloud(scale=2,max_font_size = 100) 11wc.generate_from_text(text) 12# 顯示圖像 13plt.imshow(wc,interpolation='bilinear') 14plt.axis('off') 15plt.tight_layout() 16#存儲圖像 17wc.to_file('1900_basic.png') 18# or 19# plt.savefig('1900_basic.png',dpi=200) 20plt.show()
這裡,通過 open() 方法讀取文本文件,然後在 WordCloud 方法中設置了詞雲參數,再利用 generate_from_text() 方法生成該電影劇本的詞雲,最後顯示和保存詞雲圖。十幾行代碼就可以生成最簡單的詞雲圖:

通過上面的詞雲圖,你可能會發現有幾點問題:
- 可不可以更換背景,比如白色?
- 詞雲圖能不能換成其他形狀或者圖片?
- 詞雲中最顯眼的詞彙 「ONE」,並沒有實際含義,能不能去掉?
以上這些都是可以更改的,如果你想實現以上想法,那麼需要先了解一下 WordCloud 的API 參數及它的一些方法。
這裡,我們列出它的各項參數,並注釋重要的幾項:
1wordcloud.WordCloud( 2 font_path=None, # 字體路徑,英文不用設置路徑,中文需要,否則無法正確顯示圖形 3 width=400, # 默認寬度 4 height=200, # 默認高度 5 margin=2, # 邊緣 6 ranks_only=None, 7 prefer_horizontal=0.9, 8 mask=None, # 背景圖形,如果想根據圖片繪製,則需要設置 9 scale=1, 10 color_func=None, 11 max_words=200, # 最多顯示的詞彙量 12 min_font_size=4, # 最小字號 13 stopwords=None, # 停止詞設置,修正詞雲圖時需要設置 14 random_state=None, 15 background_color='black', # 背景顏色設置,可以為具體顏色,比如white或者16進制數值 16 max_font_size=None, # 最大字號 17 font_step=1, 18 mode='RGB', 19 relative_scaling='auto', 20 regexp=None, 21 collocations=True, 22 colormap='viridis', # matplotlib 色圖,可更改名稱進而更改整體風格 23 normalize_plurals=True, 24 contour_width=0, 25 contour_color='black', 26 repeat=False)
關於更詳細的用法,你需要到官網了解。
了解了各項參數後,我們就可以自定義想要的詞雲圖了。比如更換一下背景顏色和整體風格,就可以通過修改以下幾項參數實現:
1wc = WordCloud( 2 scale=2,# 縮放2倍 3 max_font_size = 100, 4 background_color = '#383838',# 灰色 5 colormap = 'Blues') 6# colormap名稱 https://matplotlib.org/examples/color/colormaps_reference.html
結果如下:

接下來,我們提升一點難度,通過設置 StopWords 去掉沒有實際意義的「ONE」字符,然後將詞雲圖繪製在我們自定義的一張圖片上。

代碼實現如下:
1import os 2from os import path 3import numpy as np 4from wordcloud import WordCloud,STOPWORDS,ImageColorGenerator 5from PIL import Image 6from matplotlib import pyplot as plt 7from scipy.misc import imread 8import random 9 10def wc_english(): 11 # 獲取當前文件路徑 12 d = path.dirname(__file__) if "__file__" in locals() else os.getcwd() 13 # 獲取文本text 14 text = open(path.join(d,'legend1900.txt')).read() 15 # 讀取背景圖片 16 background_Image = np.array(Image.open(path.join(d, "mask1900.jpg"))) 17 # or 18 # background_Image = imread(path.join(d, "mask1900.jpg")) 19 # 提取背景圖片顏色 20 img_colors = ImageColorGenerator(background_Image) 21 # 設置英文停止詞 22 stopwords = set(STOPWORDS) 23 wc = WordCloud( 24 margin = 2, # 設置頁面邊緣 25 mask = background_Image, 26 scale = 2, 27 max_words = 200, # 最多詞個數 28 min_font_size = 4, # 最小字體大小 29 stopwords = stopwords, 30 random_state = 42, 31 background_color = 'white', # 背景顏色 32 max_font_size = 150, # 最大字體大小 33 ) 34 # 生成詞雲 35 wc.generate_from_text(text) 36 # 等價於 37 # wc.generate(text) 38 # 根據圖片色設置背景色 39 wc.recolor(color_func=img_colors) 40 #存儲圖像 41 wc.to_file('1900pro1.png') 42 # 顯示圖像 43 plt.imshow(wc,interpolation='bilinear') 44 plt.axis('off') 45 plt.tight_layout() 46 plt.show()
這裡,首先通過 open() 方法讀取文本文件,Image.open() 方法讀取了背景圖片,np.array 方法將圖片轉換為矩陣。
接着設置了詞雲自帶的英文 StopWords 停止詞,用來分割篩除文本中不需要的詞彙,比如:a、an、the 這些。
然後,在 WordCloud 方法中,設置詞雲的具體參數。generate_from_text() 方法生成該詞雲,recolor() 則是根據圖片色彩繪製詞雲文字顏色。最終的詞雲繪製效果如下:

現在,我們還是看到了顯眼的「ONE」,下面我們將它去除掉,方法也很簡單,幾行代碼就可以實現:
1# 獲取文本詞排序,可調整 stopwords 2process_word = WordCloud.process_text(wc,text) 3sort = sorted(process_word.items(),key=lambda e:e[1],reverse=True) 4print(sort[:50]) # 獲取文本詞頻最高的前50個詞 5# 結果 6[('one', 60), ('ship', 47), ('Nineteen Hundred', 43), ('know', 38), ('music', 36), ...] 7 8stopwords = set(STOPWORDS) 9stopwords.add('one')
首先,我們對文本詞頻進行排序,可以看到 「ONE」詞頻最高,就將它添加進 stopwords 中,這樣就可以屏蔽該詞從而不在詞雲中顯示。
需要注意的是,這種手動添加停止詞的方法適用於詞數量比較少的情況。

另外,我們還可以將詞雲圖顏色顯示為黑白漸變色,也只需修改幾行代碼即可:
1def grey_color_func(word, font_size, position, orientation, random_state=None, 2 **kwargs): 3 return "hsl(0, 0%%, %d%%)" % random.randint(50, 100) 4 # 隨機設置hsl色值 5wc.recolor(color_func=grey_color_func)
效果如下:

以上,就是英文詞雲圖繪製的幾種方法,下面我們介紹中文詞雲圖的繪製。
2. 中文詞雲
相比於英文詞雲,中文在繪製詞雲圖前,需要先切割詞彙,這裡推薦使用 jieba 包來切割分詞。因為它可以說是最好的中文分詞包了,GitHub 上擁有 160 K 的 Star 數。安裝好 jieba 包後,我們就可以對文本進行分詞然後生成詞雲。
這裡,選取吳軍老師的著作《浪潮之巔》作為中文文本的案例,仍然採用圖片形式的詞雲圖。素材準備好後,接下來就可以開始中文詞雲圖繪製。

首先,需要讀取文本文件,相比於英文,這裡要添加文本編碼格式,否則會報錯,添加幾行代碼就可以識別文本的編碼格式:
1text = open(path.join(d,'langchao.txt'),'rb').read() 2text_charInfo = chardet.detect(text) 3print(text_charInfo) 4# 結果 5{'encoding': 'UTF-8-SIG', 'confidence': 1.0, 'language': ''} 6text = open(path.join(d,r'langchao.txt'),encoding='UTF-8-SIG').read()
接着,對文本進行分詞。jieba 分詞有 3 種方式:精確模式、全模式和搜索引擎模式,它們之間的差別,可以用一個例子來體現。
比如,有這樣的一句話:「"我來到北京清華大學"」,用 3 種模式進行分詞,結果分別如下:
- 全模式: 我/ 來到/ 北京/ 清華/ 清華大學/ 華大/ 大學
- 精確模式: 我/ 來到/ 北京/ 清華大學
- 搜索引擎模式: 我/ 來/ 來到/ 北京/ 清華/ 大學/ 清華大學/
根據結果可知,我們應該選擇「精確模式」來分詞。關於 jieba 包的詳細用法,可以參考 GitHub 倉庫鏈接:
https://github.com/fxsjy/jieba
分詞完成後,還需要設置 stopwords 停止詞,由於 WordCloud 沒有中文停止詞,所以需要自行構造。這裡可以採取兩種方式來構造:
- 通過 stopwords.update() 方法手動添加
- 根據已有 stopwords 詞庫遍歷文本篩除停止詞
2.1. stopwords.update() 手動添加
這種方法和前面的英文停止詞構造的方法是一樣的,目的是在詞雲圖中不顯示 stopwords 就行了 ,即先不設置 stopwords,而是先對文本詞頻進行排序,然後將不需要的詞語添加為 stopwords 即可,代碼實現如下:
1# 獲取文本詞排序,可調整 stopwords 2process_word = WordCloud.process_text(wc,text) 3sort = sorted(process_word.items(),key=lambda e:e[1],reverse=True) 4print(sort[:50]) # # 獲取文本詞頻最高的前50個詞 5 6[('公司', 1273), ('但是', 769), ('IBM', 668), ('一個', 616), ('Google', 429), ('自己', 396), ('因此', 363), ('微軟', 358), ('美國', 344), ('沒有', 334)...]
可以看到,我們先輸出文本詞頻最高的一些詞彙後,發現:「但是」、「一個」、「因此」這些詞都是不需要顯示在詞雲圖中的。因此,可以把這些詞用列表的形式添加到 stopwords 中,然後再次繪製詞雲圖就能得出比較理想的效果,完整代碼如下:
1import chardet 2import jieba 3text+=' '.join(jieba.cut(text,cut_all=False)) # cut_all=False 表示採用精確模式 4# 設置中文字體 5font_path = 'C:WindowsFontsSourceHanSansCN-Regular.otf' # 思源黑體 6# 讀取背景圖片 7background_Image = np.array(Image.open(path.join(d, "wave.png"))) 8# 提取背景圖片顏色 9img_colors = ImageColorGenerator(background_Image) 10# 設置中文停止詞 11stopwords = set('') 12stopwords.update(['但是','一個','自己','因此','沒有','很多','可以','這個','雖然','因為','這樣','已經','現在','一些','比如','不是','當然','可能','如果','就是','同時','比如','這些','必須','由於','而且','並且','他們']) 13 14wc = WordCloud( 15 font_path = font_path, # 中文需設置路徑 16 margin = 2, # 頁面邊緣 17 mask = background_Image, 18 scale = 2, 19 max_words = 200, # 最多詞個數 20 min_font_size = 4, # 21 stopwords = stopwords, 22 random_state = 42, 23 background_color = 'white', # 背景顏色 24 # background_color = '#C3481A', # 背景顏色 25 max_font_size = 100, 26 ) 27wc.generate(text) 28# 獲取文本詞排序,可調整 stopwords 29process_word = WordCloud.process_text(wc,text) 30sort = sorted(process_word.items(),key=lambda e:e[1],reverse=True) 31print(sort[:50]) # 獲取文本詞頻最高的前50個詞 32# 設置為背景色,若不想要背景圖片顏色,就注釋掉 33wc.recolor(color_func=img_colors) 34# 存儲圖像 35wc.to_file('浪潮之巔basic.png') 36# 顯示圖像 37plt.imshow(wc,interpolation='bilinear') 38plt.axis('off') 39plt.tight_layout() 40plt.show()
stopwords 添加之前:

stopwords 添加之後:

可以看到,stopwords.update() 這種方法需要手動去添加,比較麻煩一些,而且如果 stopwords 過多的話,添加就比較費時了。下面介紹第 2 種自動去除 stopwords 的方法。
2.2. stopwords 庫自動遍歷刪除
這種方法的思路也比較簡單,主要分為 2 個步驟:
- 利用已有的中文 stopwords 詞庫,對原文本進行分詞後,遍歷詞庫去除停止詞,然後生成新的文本文件。
- 根據新的文件繪製詞雲圖,便不會再出現 stopwords,如果發現 stopwords 詞庫不全可以進行補充,然後再次生成詞雲圖即可。
代碼實現如下:
1# 對原文本分詞 2def cut_words(): 3 # 獲取當前文件路徑 4 d = path.dirname(__file__) if "__file__" in locals() else os.getcwd() 5 text = open(path.join(d,r'langchao.txt'),encoding='UTF-8-SIG').read() 6 text = jieba.cut(text,cut_all=False) 7 content = '' 8 for i in text: 9 content += i 10 content += " " 11 return content 12 13# 加載stopwords 14def load_stopwords(): 15 filepath = path.join(d,r'stopwords_cn.txt') 16 stopwords = [line.strip() for line in open(filepath,encoding='utf-8').readlines()] 17 # print(stopwords) # ok 18 return stopwords 19 20# 去除原文stopwords,並生成新的文本 21def move_stopwwords(content,stopwords): 22 content_after = '' 23 for word in content: 24 if word not in stopwords: 25 if word != 't'and'n': 26 content_after += word 27 28 content_after = content_after.replace(" ", " ").replace(" ", " ") 29 # print(content_after) 30 # 寫入去停止詞後生成的新文本 31 with open('langchao2.txt','w',encoding='UTF-8-SIG') as f: 32 f.write(content_after)
網上有很多中文 stopwords 詞庫資料,這裡選取了一套包含近 2000 個詞彙和標點符號的詞庫:stopwords_cn.txt,結構形式如下:

遍歷該 stopwords 詞庫,刪除停止詞獲得新的文本,然後利用第一種方法繪製詞雲圖即可。
首先輸出一下文本詞頻最高的部分詞彙,可以看到常見的停止詞已經沒有了:
1[('公司', 1462), ('美國', 366), ('IBM', 322), ('微軟', 320), ('市場', 287), ('投資', 263), ('世界', 236), ('硅谷', 235), ('技術', 234), ('發展', 225), ('計算機', 218), ('摩托羅拉', 203)...]
詞雲圖最終效果如下:

3. Frenquency 詞雲圖
上面兩種中英文詞雲圖都是通過文本繪製的,而除了直接讀入文本生成詞雲以外,比較常見的還有通過「詞頻」繪製詞雲圖。這種詞雲圖,則可以使用 DataFrame 或者 字典格式 來繪製。
下面,以此前我們爬過的一篇「近十年 世界大學排名 TOP500 強」教程的數據為例,介紹如何繪製詞頻詞雲圖。
該份數據大小為 5001行 x 6 列,我們想根據各國 TOP 500 強大學的數量,來可視化地展示各國之間的大學數量差異。
1world_rank university score quantity year country 21 哈佛大學 100 500 2009 USA 32 斯坦福大學 73.1 499 2009 USA 43 加州大學-伯克利 71 498 2009 USA 54 劍橋大學 70.2 497 2009 UK 65 麻省理工學院 69.5 496 2009 USA 7... 8496 猶他州立大學 2018 USA 9497 聖拉斐爾生命健康大學 2018 Italy 10498 早稻田大學 2018 Japan 11499 韋恩州立大學 2018 USA 12500 西弗吉尼亞大學 2018 USA
這裡,有兩種方式可以直接生成頻率詞雲圖,第一種是 利用 Series 列表生成,代碼實現如下:
1import pandas as pd 2import matplotlib.dates as mdate 3from wordcloud import WordCloud 4import matplotlib.pyplot as plt 5 6df = pd.read_csv('university.csv',encoding = 'utf-8') 7df = df.groupby(by = 'country').count() 8df = df['world_rank'].sort_values(ascending = False) 9print(df[:10]) 10# 結果如下: 11country 12USA 1459 13Germany 382 14UK 379 15China 320 16France 210 17Canada 209 18Japan 206 19Australia 199 20Italy 195 21Netherlands 122
第二種方式是轉換為 dict 字典生成,一行代碼就可以完成:
1df = dict(df) 2print(df) 3# 結果如下: 4{'USA': 1459, 'Germany': 382, 'UK': 379, 'China': 320, 'France': 210,..}
數據轉換好以後,就可以生成詞雲圖了,代碼實現如下:
1font_path='C:WindowsFontsSourceHanSansCN-Regular.otf' # 思源黑 2wordcloud = WordCloud( 3 background_color = '#F3F3F3', 4 font_path = font_path, 5 width = 5000, 6 height = 300, 7 margin = 2, 8 max_font_size = 200, 9 random_state = 42, 10 scale = 2, 11 colormap = 'viridis', # 默認virdis 12 ) 13wordcloud.generate_from_frequencies(df) 14# or 15# wordcloud.fit_words(df) 16plt.imshow(wordcloud,interpolation = 'bilinear') 17plt.axis('off') 18plt.show()
效果如下:

可以看到,美國最為突出,其次是德國、英國、中國等。看來,我們國內的大學還得加把勁啊。
以上,就是繪製詞雲圖常見的幾種方式。
本文完。
文中代碼可以在下面的鏈接中獲取:
https://github.com/makcyun/eastmoney_spider