Windows環境下Python中wordcloud的使用——自己踩過的坑 2017.08.08

Python-wordcloud-初次嘗試

作爲一個Python初學者,作爲學習的開始,這次我根據《一件有趣的事:用Python 爬了爬自己的微信朋友》中的方法測試了一遍效果。這裏記錄下目前用的wordcloud這個包時遇到的一些問題吧。(具體執行的完整代碼我就不放進來了,反正也是依據鏈接中寫的爲主。)

使用wordcloud可以方便地生成雲詞圖,這在數據可視化的方面會給我們帶來很多便利。

看別人教程寫的各種順,然而實際操作起來才發現,初學者還是容易遇到很多坑。


說明

環境:

已安裝Anaconda3 (64-bit) 4.4.0Python 3.6.1)。其中,代碼調試在Spyder 3.1.4中進行,安裝包則直接打開Anaconda Prompt調用cmd.exe後進行。

系統爲Windows 7 和 Windows 10。


安裝包的坑

安裝文件的獲取

首先,安裝包時,直接用 pip install wordcloud是會報錯的,會有文件缺失的問題。這一點不少人都有類似反饋。

解決方案:

github下載wordcloud的包,解壓縮後,在對應目錄下用python setup.py install安裝。

VC++ 14的缺失問題

安裝wordcloud時出現報錯信息:

error: Microsoft Visual C++ 14.0 is required. Get it with “Microsoft Visual C++ Build Tools”: http://landinghub.visualstudio.com/visual-cpp-build-tools

這種情況下,其實直接跟着提示內容進行就好。

解決方案:

打開報錯提示中的鏈接,下載並安裝Visual C++ 2015 Build Tools

這個問題,我在一臺電腦上這樣解決(成功安裝了wordcloud包並正常調試了相關Python代碼)之後,嘗試在另一臺電腦上再安裝該包,結果出現了新問題:Visual C++ 2015 Build Tools,從官網下載下來的安裝程序visualcppbuildtools_full.exe,打開後在安裝過程中需要聯網獲取文件,但是由於網絡限制導致無法獲取,於是無法安裝!並且沒有搜到含有完整安裝文件的包。(注:該電腦所處的網絡環境不一樣,一般網頁中的文件下載沒問題,但是build tools安裝時聯網獲取文件就受限制而不成功。)

離線安裝VC++14.0 build tools的解決方案:

  • 在能正常通過visualcppbuildtools_full.exe 聯網獲取安裝文件的電腦上,在系統自帶的cmd.exe中在對應目錄下執行:
visualcppbuildtools_full.exe /layout

之後,選擇下載目錄存放離線安裝包,然後就可以把安裝文件下載下來了。

  • 然後在不能聯網安裝的電腦上,安裝離線包即可。

此處是參考msdn上找到的方法。

其它嘗試

當遇到安裝Visual C++ 2015 Build Tools無法獲取安裝文件時(visualcppbuildtools_full.exe 只有3M,卻提示默認安裝的話需要4G空間,可想而知需要下載不少安裝文件,實際上最後下載的安裝文件也有2G左右),曾經嘗試過是否可以不安裝4G這麼大的build tools而只安裝VC++14的運行庫,畢竟應該只是缺庫吧?

畢竟,實際上運行庫Microsoft Visual C++ 2015 Redistributable Update 3下載鏈接在此)的安裝程序只有十幾M大小,並且能夠正常下載安裝。

但我試下來的結果是,安裝了這個東西以後依然會有前面一樣的報錯。所以還是繼續老老實實下載了完整的build tools。如果你有更好的方案(不用安裝這個佔4G左右的大傢伙,不用藉助另一個網絡環境下的電腦),可以和我留言。

備註

github下載到的原wordcloud安裝包中,提到如果安裝還是有問題的的話可以試試安裝鏈接中的.whl文件。

不過,我是沒下載這個.whl文件的,前面講到的坑補完就好了。


字體的坑

Win10和Win7的默認字體後綴竟然不一樣

生成雲詞圖的過程中,自己設置字體爲“微軟雅黑 粗體”,在系統(Win10)路徑中找到了這個字體的路徑“C:\Windows\Fonts\msyhbd.ttc”

沒想到,代碼複製到第二臺電腦(Win7)下執行時卻報錯。本來以爲都是Windows默認庫裏的字體應該沒什麼問題,打開一看才發現Win7這裏的字體後綴是“ttf”

改過就正常了。

提醒以後注意:

哪怕是Windows上執行過沒問題的代碼,換個同樣Windows的電腦,也要注意 系統默認路徑和相關文件 是否有變化!

並不是全默認就都一樣啊啊啊啊!!!


遮罩底圖的坑

錯誤提示Gray-scale?

NotImplementedError: Gray-scale images TODO

一開始,我用的底圖會出現如上報錯。

如果把出錯的如下這行

plt.imshow(my_wc.recolor(color_func=i_colors))

去掉,那麼就不會報錯,但是生成的雲詞圖會只有形狀、沒有原圖的顏色。

出現報錯時用的底圖如下:
用這個圖會報錯

這個圖片有什麼問題呢?爲什麼會有“Gray-scale images”這種提示,難道我這個圖的灰度有問題?明明好幾個顏色啊好嗎?甚至我專心弄了個純黑白的圖,發現純黑白色底圖都能正常執行代碼。

不過,把上面出錯的圖,和兩個不出錯的圖對比一下讀取後的數據,就能看出問題在哪裏了。

如下圖所示:

coloring0=np.array(Image.open("出錯圖.png")) #問題圖,實際上,下面的白底“底圖1”就是將該圖直接截圖保存生成的
coloring1=np.array(Image.open("後面附上不同背景測試圖對比的底圖1.bmp")) #白底
coloring2=np.array(Image.open("後面附上不同背景測試圖對比的底圖2.png")) #透明底

coloring0是出錯的圖

覈查報錯位置源代碼:

class ImageColorGenerator(object):
......#此處省略很多代碼
 def __call__(self, word, font_size, font_path, position, orientation, **kwargs):
 ......#此處省略很多代碼
        if patch.ndim == 2:
            raise NotImplementedError("Gray-scale images TODO")
 ......#此處省略很多代碼

這就可以確定這個報錯只因 “維度爲2” 引起的。

哦,終於明白這個“Gray-scale”是什麼鬼了。這貨,每個點都只有2個值來表明顏色啊。後面白底的圖,沒有透明色,每個點也是正常的3個值;透明底的圖,多了第4個值來表示透明度。而這個“沒有Gray-scale的圖”,應該就是沒有灰度參數吧?之前選圖時候還真沒注意這點,畢竟我也不是學美術出身,乍一眼也看不出來這個圖的顏色沒有灰度所以有可能沒有灰度參數啊。

解決方案:

對於新手小白,如果不想在讀取圖像後直接改Value加一列的話,最簡單的操作就是換個能用的圖再執行吧。

如果確定就是隻要這個圖的樣子,那麼可以轉化格式,或者再不行截個圖保存再用也是可以的。

總之,這個報錯的原因,不是代碼問題,僅僅是圖的格式問題


圖片輸出的坑

圖片沒有正常顯示 新手關於plt.savefig的用法

這裏我用plt.savefig("這裏是生成圖片的路徑")來存儲生成的雲詞圖。

一開始,將plt.savefig放在plt.show之後,結果只是生成了空白的圖。後來在這篇文章《【Python】解決使用plt.savefig保存圖片時一片空白》中瞭解到:

“在plt.show() 後實際上已經創建了一個新的空白的圖片(座標軸),這時候你再plt.savefig() 就會保存這個新生成的空白圖片。”

所以,只要把plt.savefig放在plt.show之前即可解決這個問題。

我生成雲詞圖的最後幾行代碼如下:

plt.imshow(my_wc)
plt.axis("off")
plt.savefig("H:/temp/temp.jpg",dpi=200) #用反斜槓的話會報錯
plt.show()

另一種輸出圖像的方式 .to_file

WordCloud中,自帶.to_file可以將雲詞圖輸出到文件。

具體方法:將上述代碼中plt.savefig一行替換爲

my_wc.to_file("H:/temp/temp.jpg")

即可。

可以發現兩種輸出方式的區別:
- plt.savefig默認尺寸是和終端中顯示差不多的縮略版的圖(大小432×288),可以通過dpi調節精度改善清晰度,具體可見本文中“圖片大小和精度的影響”的描述。
- .to_file,則輸出的是每個字都精確顯示的完整雲詞圖,非常清晰,放大後可以看到連最小的字都是清晰完整地顯示,當然默認尺寸也很大。

爲方便對比,可見本文後面WordCloud參數的調節這部分裏scale=2(使用plt.savefig輸出,dpi=200)、scale=32(使用plt.savefig輸出,dpi=200)、scale=2(使用.to_file輸出)的3個雲詞圖。

生成圖像清晰度的調節

圖片大小和精度的影響

因爲這次用plt.savefig默認生成的圖感覺不是很清晰,尺寸不夠大,所以這裏在plt.savefig中加上了參數dpi調整精度。

當然,同樣一張圖,精度越高,自然尺寸也是越大的。

不過,至於精度調整成多少合適(只爲了肉眼看起來清晰),是看情況而定。雖然理論上精度越大就越清晰,但是在遮罩圖、詞數量等因素確定的情況下,有時候更大的精度只是把圖的尺寸放大,但肉眼可見的清晰程度並不會真的就提高。

如果圖太小太密集,那麼可能是默認精度的侷限導致不清晰。需要調整精度參數dpi放大圖片。

但是如果圖片足夠大,字看起來也不小,但是仍然不清晰,或者佈局不自然,那麼有可能是雲詞圖生成時本身的參數設置問題。可見下面的描述。

WordCloud參數的調節

import matplotlib.pyplot as plt
from wordcloud import WordCloud,ImageColorGenerator
import numpy as np
import PIL.Image as Image

coloring=np.array(Image.open("H:\temp\meerca_2.png"))
my_wc=WordCloud(background_color="white",max_words=2000,
                mask=coloring, max_font_size=60,random_state=42,scale=8,
                font_path="C:\Windows\Fonts\msyhbd.ttf").generate(word_space_split)  #這裏word_space_split是前面生成的以空格分割的需要生成雲詞的詞庫字符串(str)

這裏簡要講下幾個會影響圖像清晰問題的WordCloud的參數:

  • mask遮罩圖,字的大小布局和顏色都會依據遮罩圖生成。其實理論上這對字大小和清晰程度的影響不大,但是遮罩圖色和背景色background_color如果易混淆,則可能是一個導致看起來不清晰的因素;另外遮罩圖自身各個顏色之間的對比不強烈,也可能使圖看起來層次感不夠。

    • 比如,一些圖明度比較高,再加上背景白色,有可能導致字色太淺(背景色background_color又是白色)於是看起來不夠“清晰”。
  • background_color背景色,默認。這個本來其實也不怎麼影響清晰度,但是,就像之前在mask中提到的,如果遮罩圖像顏色過淺、背景設置白色,可能導致字看起來“不清晰”。而實際上,我對一個淺色遮罩圖分別用白、黑兩種背景色後發現,黑色背景的強烈對比之下會有若干很淺也很小的詞浮現出來,而之前因背景色、字色過於相近而幾乎無法用肉眼看出這些詞

  • mode:默認“RGB”。根據說明文檔,如果想設置透明底色的雲詞圖,那麼可以設置background_color=None, mode="RGBA"
    • 但是!!!實際中我嘗試設置透明背景色並沒有成功過
      • 當我選取的遮罩圖是白色底時,如果background_color設置爲"white""black"時,生成的雲詞確實是對應的“白色”“黑色”;但是按照上述參數設置透明色時,結果出來依然是白色
      • 當我選取的遮罩圖是透明底時,那麼不管我background_color設置爲"white""black",還是None加上mode="RGBA",結果都是把背景部分當做黑色圖塊,自動匹配黑色的字!——也就是並沒有實現透明底的雲詞。
      • 誰如果實現了透明底色的方案,歡迎給我留言。目前這個疑惑我打算先不研究了,放到以後再看。

底圖1(白底,640×435):
底圖1(白底,640×435)
底圖2(透明底,300×300):
底圖2(透明底,300×300)
底圖1與底圖2生成雲詞圖效果對比,除background_colormode參數以外其它參數不變:
白底和透明底圖,配不同的background_color和mode參數對比
注:1. 兩個底圖尺寸也有點區別。生成的圖片是用plt.savefig(參數dpi=200),也可以看出生成圖在佈局上有差異。2. 本文中,其它雲詞圖實例中,均是使用“底圖1”(本身是白色底)這個圖。

  • max_font_size最大字號。源文件中也有講到,圖的生成會依據最大字號等因素去自動判斷詞的佈局。經測試,哪怕同一個圖像,只要圖本身尺寸不一樣(比如我把一個300×300的圖拉大到600×600再去當遮罩),那麼同樣的字號也是會有不同的效果。原理想想也很自然,字號決定了字的尺寸,而圖的尺寸變了以後,最大字相對於圖的尺寸比例自然就變了。所以,需要根據期望顯示的效果,去調整最大字號參數值
    • 相對應的參數min_font_size最小字號。不設置的情況下,默認是4。嘗試了設置比4大的字號,例如8、10,結果就是原本小於設定值且大於4號的詞都直接不顯示了,其它內容和未設置該值時都一樣
  • relative_scaling:表示詞頻和雲詞圖中字大小的關係參數,默認0.5。爲0時,表示只考慮詞排序,而不考慮詞頻數;爲1時,表示兩倍詞頻的詞也會用兩倍字號顯示。本文中的案例,均用的默認值,未特別設置該參數。
  • scale:根據說明文檔,當雲詞圖很大的,加大該值會比使用更大的圖更快,但值越高也會越慢(計算更復雜)。默認值是1。實際測試中,更大的值,確實輸出圖像看起來更精細(較小較淺的詞會顏色更重,也感覺清楚,大的詞差異不明顯)。不過,可能由於我選的圖不大、詞也沒有很多,所以差距並沒有很大,縮小排列一下就基本上辨別不出多少差別了。
    • 經測試發現,在詞沒有很多(這裏len(word_space_split)=6310)和圖沒有很大的情況下,詞不變,圖不變,則scale越大,運行速度越慢。實際上,本案例中取“32”時已經比“2”慢了很多秒,這個時間差可以體會體會到,本文暫不對時間差和效率問題進行精確研究了。
    • 另外經測試發現,其它參數完全相同情況下,scale越大,圖片佔空間越小。這裏scale分別取“2”“10”“32”時,獲得的圖片大小分別爲207K、110K、75.8K。(這裏圖用plt.savefig輸出,dpi=200,實際輸出尺寸爲1200×800。)
    • 下面選取底圖1時scale分別取“2”“10”“32”的縮略效果(其實我還試了“64”,但是一跑代碼電腦就卡了,卡到別的進程都無法切到的程度,若干分鐘後實在等不了了強制結束,卡到Crtl+C都不反應、只能強制從任務管理器結束進程而且按了很久纔有反應,呵呵噠):

scale=2, scale=10, scale=32 對比
是不是沒看出什麼區別?那麼下面放下“2”“32”對應的雲詞圖本身。

scale=2的雲詞圖如下(使用plt.savefig輸出,dpi=200):
scale=2

scale=32的雲詞圖如下(使用plt.savefig輸出,dpi=200):
scale=32

scale=2的雲詞圖如下(使用.to_file輸出):
用.to_file輸出

注:可以注意上面3個圖中,右上方“唯有”字樣的右上角“如同”字樣(較小字)的顯示差異,進行對比。

  • random_state:不同的值會讓字圖的分佈不一樣。

不同random_state的效果對比

*注:本文的雲詞圖案例中,詞庫裏“1f60a”之類的字符沒有去掉,這些本來是代表某些emoji的。我個人覺得這不算亂碼吧,所以留着了。
1f60a

  • 更多參數的設置,可參看源文件中的說明

*附上源文件wordcloud.py中對WordCloud這一函數的各個參數的解釋:

Word cloud object for generating and drawing.

    Parameters
    ----------
    font_path : string
        Font path to the font that will be used (OTF or TTF).
        Defaults to DroidSansMono path on a Linux machine. If you are on
        another OS or don't have this font, you need to adjust this path.

    width : int (default=400)
        Width of the canvas.

    height : int (default=200)
        Height of the canvas.

    prefer_horizontal : float (default=0.90)
        The ratio of times to try horizontal fitting as opposed to vertical.
        If prefer_horizontal < 1, the algorithm will try rotating the word
        if it doesn't fit. (There is currently no built-in way to get only
        vertical words.)

    mask : nd-array or None (default=None)
        If not None, gives a binary mask on where to draw words. If mask is not
        None, width and height will be ignored and the shape of mask will be
        used instead. All white (#FF or #FFFFFF) entries will be considerd
        "masked out" while other entries will be free to draw on. [This
        changed in the most recent version!]

    scale : float (default=1)
        Scaling between computation and drawing. For large word-cloud images,
        using scale instead of larger canvas size is significantly faster, but
        might lead to a coarser fit for the words.

    min_font_size : int (default=4)
        Smallest font size to use. Will stop when there is no more room in this
        size.

    font_step : int (default=1)
        Step size for the font. font_step > 1 might speed up computation but
        give a worse fit.

    max_words : number (default=200)
        The maximum number of words.

    stopwords : set of strings or None
        The words that will be eliminated. If None, the build-in STOPWORDS
        list will be used.

    background_color : color value (default="black")
        Background color for the word cloud image.

    max_font_size : int or None (default=None)
        Maximum font size for the largest word. If None, height of the image is
        used.

    mode : string (default="RGB")
        Transparent background will be generated when mode is "RGBA" and
        background_color is None.

    relative_scaling : float (default=.5)
        Importance of relative word frequencies for font-size.  With
        relative_scaling=0, only word-ranks are considered.  With
        relative_scaling=1, a word that is twice as frequent will have twice
        the size.  If you want to consider the word frequencies and not only
        their rank, relative_scaling around .5 often looks good.

        .. versionchanged: 2.0
            Default is now 0.5.

    color_func : callable, default=None
        Callable with parameters word, font_size, position, orientation,
        font_path, random_state that returns a PIL color for each word.
        Overwrites "colormap".
        See colormap for specifying a matplotlib colormap instead.

    regexp : string or None (optional)
        Regular expression to split the input text into tokens in process_text.
        If None is specified, ``r"\w[\w']+"`` is used.

    collocations : bool, default=True
        Whether to include collocations (bigrams) of two words.

        .. versionadded: 2.0

    colormap : string or matplotlib colormap, default="viridis"
        Matplotlib colormap to randomly draw colors from for each word.
        Ignored if "color_func" is specified.

        .. versionadded: 2.0

    normalize_plurals : bool, default=True
        Whether to remove trailing 's' from words. If True and a word
        appears with and without a trailing 's', the one with trailing 's'
        is removed and its counts are added to the version without
        trailing 's' -- unless the word ends with 'ss'.

    Attributes
    ----------
    ``words_`` : dict of string to float
        Word tokens with associated frequency.

        .. versionchanged: 2.0
            ``words_`` is now a dictionary

    ``layout_`` : list of tuples (string, int, (int, int), int, color))
        Encodes the fitted word cloud. Encodes for each word the string, font
        size, position, orientation and color.

    Notes
    -----
    Larger canvases with make the code significantly slower. If you need a
    large word cloud, try a lower canvas size, and set the scale parameter.

    The algorithm might give more weight to the ranking of the words
    than their actual frequencies, depending on the ``max_font_size`` and the
    scaling heuristic.

【完】


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