WordCloud 中英文詞雲圖繪製,看這一篇就夠了

文章轉載自「第2大腦」

摘要: 當我們手中有一篇文檔,比如書籍、小說、電影劇本,若想快速瞭解其主要內容是什麼,則可以採用繪製 WordCloud 詞雲圖,顯示主要的關鍵詞(高頻詞)這種方式,非常方便。本文將介紹常見的英文和中文文本的詞雲圖繪製,以及 Frequency 頻詞頻詞雲圖。

這篇文章中詳細說明各種形式的詞雲圖繪製步驟。

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:\Windows\Fonts\SourceHanSansCN-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:\Windows\Fonts\SourceHanSansCN-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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章