JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

jb發表於2018-06-12

一句話概括

本文通過實戰圍繞介紹使用jieba庫進行中文分詞,並使用collections模組進行分詞的次數統計,介紹了wordcloud詞雲庫的使用方式;

前言

爬蟲獲取資料後,就需要資料分析了,那資料怎麼處理?用到什麼資料?一起來看看吧~

最近又重新看回了全職高手這部小說及動漫,猶記得當時被劉老師安利,說這小說很好看,後來騰訊買了版權,出了動畫,雖然有刪減,但依然有空看幾遍;
但有時候也在想,為什麼自己那麼沉迷這小說,除了裡面寫的遊戲基本跟讀書時玩的DNF一樣外,應該沒其他特別的;
既然如何?有沒有辦法把小說裡的內容進行提取關鍵字,然後再弄個詞雲?
這不就找到了jieba&wordcloud庫嗎?

1 資料準備:

直接網上找全職高手txt下載,一大堆,解壓後獲取到txt檔案;
全職高手txt小說下載地址

1.2 讀取全職高手文字

with open("quanzhigaoshou.txt") as f:
    qzgs_text = f.read()
print(len(qzgs_text))
複製程式碼

結果直接執行,報錯了

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)
沒毛病,編碼問題,open時指定下utf-8即可:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)
看了下,整個文字的長度有 8623554 個位元組,資料量非常可觀,感覺題材會很豐富的~

這是不是就準備好了呢?
答案是NO,因為文字內容是這樣的:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

從上圖可以看出,文字里面會有各種符號跟廣告,目前這步,要做的就是把各種標點符號幹掉先;

with open("quanzhigaoshou.txt",encoding='utf-8') as f:
    qzgs_text = f.read()
pattern = re.compile('[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?“”、~@#¥%……&*()(\d+)]+')
new_qzgs_text = pattern.sub("",qzgs_text)
print(new_qzgs_text)
複製程式碼

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

到此,字串搞定啦~

1.3 jieba中文分詞庫

因為我們的樣例都是中文,因此就選用據說是最好的python中文分詞庫jieba

  • GitHub倉庫:https://github.com/fxsjy/jieba
  • 官方文件:https://pypi.org/project/jieba/
  • 一個比較詳細的教程:https://blog.csdn.net/fontthrone/article/details/72782499

二話不說,直接安裝一波先:

pip install jieba
複製程式碼

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

安裝過程沒什麼好說的;目前暫未遇到問題

官方提供的特點:

  • 支援三種分詞模式:
    • 精確模式,試圖將句子最精確地切開,適合文字分析;
    • 全模式,把句子中所有的可以成詞的詞語都掃描出來,速度非常快,但是不能解決歧義;
    • 搜尋引擎模式,在精確模式的基礎上,對長詞再次切分,提高召回率,適合用於搜尋引擎分詞。

這裡貼一個官方的例子:

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_for_search("小明碩士畢業於中國科學院計算所,後在日本京都大學深造")  # 搜尋引擎模式
print(", ".join(seg_list))
複製程式碼

輸出的結果:

【全模式】: 我/ 來到/ 北京/ 清華/ 清華大學/ 華大/ 大學
【精確模式/預設模式】: 我/ 來到/ 北京/ 清華大學
【搜尋引擎模式】:小明, 碩士, 畢業, 於, 中國, 科學, 學院, 科學院, 中國科學院, 計算, 計算所, ,, 後, 在, 日本, 京都, 大學, 日本京都大學, 深造
複製程式碼

從官網的例子可以看到,就一個cut引數裡面放需要分詞的字串跟cu_all引數,是否開啟全模式;
比如大傻叉,預設模式/精準模式,就是會辨識到大,傻,叉;
而全模式,則會變成大傻,傻叉,大傻叉這樣
當然,這個結果是想象出來的,實際並非這樣,具體原因未明,可能是沒有入詞庫導致?

ok,瞭解到jieba如何使用,就來試試把:

qzgs_word = [word for word in jieba.cut(new_qzgs_text,cut_all=False) if len(word)>2]
#這看上去很長,但很好理解,獲取分詞,然後長度大於2個才算一個詞;在遍歷下,就能
複製程式碼

寫個for把分詞遍歷下:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

沒毛病,繼續;

接下來就是統計同詞詞頻,一般來說,會統計詞出現的次數,也叫頻次;

這塊,有collections模組的Counter來實現;
Counter類的目的是用來跟蹤值出現的次數
它是一個無序的容器型別,以字典的鍵值對形式儲存,其中元素作為key,其計數作為value。

這裡介紹下Counter類的一些方法:
1)建立

c = Counter()  # 建立一個空的Counter類
c = Counter('gallahad')  # 從一個可iterable物件(list、tuple、dict、字串等)建立
c = Counter({'a': 4, 'b': 2})  # 從一個字典物件建立
c = Counter(a=4, b=2)  # 從一組鍵值對建立
複製程式碼

2)計數值的訪問與缺失的鍵 當訪問的健不存在時,返回0,否則就返回它的計數

c= Counter("abcdefgab")
print(c["a"])
print(c["c"])
print(c["h"])

輸出的結果:
2
1
0
複製程式碼

3)計算器的更新(update和subtract) 可以使用一個iterable物件或者另一個Counter物件來更新鍵值。
計數器的更新包括增加和減少兩種。其中,增加使用
update()**方法:

c= Counter("which")
c.update("witch")
print(c["h"])

d = Counter("watch")
c.update(d)
print(c["h"])

輸出的結果:
3
4
複製程式碼

減少則使用**subtract()**方法:

c= Counter("which")
c.subtract("witch")
print(c["h"])

d = Counter("watch")
c.subtract(d)
print(c["a"])

輸出的結果:
1
-1
複製程式碼

4)鍵的刪除: 當計數值為0時,並不意味著元素被刪除,刪除元素應當使用del。

c= Counter("abcdcba")
print(c)

c["b"]=0
print(c)

del c["a"]
print(c)

輸出的結果:
Counter({'a': 2, 'b': 2, 'c': 2, 'd': 1})
Counter({'a': 2, 'c': 2, 'd': 1, 'b': 0})
Counter({'c': 2, 'd': 1, 'b': 0})
複製程式碼

5)elements(): 返回一個迭代器。元素被重複了多少次,在該迭代器中就包含多少個該元素。元素排列無確定順序,個數小於1的元素不被包含。

c = Counter(a=4, b=2, c=0, d=-2)
print(list(c.elements()))

輸出的結果:
['a', 'a', 'a', 'a', 'b', 'b']
複製程式碼

6)most_common(): 返回一個TopN列表。如果n沒有被指定,則返回所有元素。當多個元素計數值相同時,排列是無確定順序的。

c= Counter("abracadabra")
print(c.most_common())
print(c.most_common(3))

輸出的結果:
[('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)]
[('a', 5), ('b', 2), ('r', 2)]
複製程式碼

還有copy跟集合算術操作,這裡就不說明了,很簡單;

扯遠了,我們的目的是跟蹤值出現的次數,根據上面的介紹,發現most_common()這個方法能符號要求;
根據上面most_common的介紹,會返回2個引數,一個是詞,一個是次數,因此只需要把這兩個玩意輸出即可: c = Counter(qzgs_words) for word in c.most_common(50): word,freq = word print(word,freq) #50代表取的TOP50 輸出的結果:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

嗯,想要的資料拿到了,但是這內容,是不是很奇怪?wwwmianhuatangla這玩意都出現了,還有小說網,看起來,是不是這種,是沒有任何意義的,那我們還需要對資料進行處理,也叫資料清洗,就是定義一個過濾列表,把想過濾的詞都扔進去,分詞遍歷後,把符合的元素進行移除即可:

invalid_words = ["所有人","看起來","小說網","wwwmianhuatangla","是不是","為什麼","沒什麼","其他人","未完待續",
                "事實上","一時間","是因為","一瞬間","只不過","差不多","不至於","這時候","越來越","沒想到","可不是","不得不","接下來",
                 "魄之力","俱樂部"]

for word in qzgs_words:
    if word in invalid_words:
        qzgs_words.remove(word)
複製程式碼

輸出是這樣的:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)
不知道為什麼,wwwmianhuatangla這玩意還是一直存在,連boss都有,只是次數有所下降了,而臨時方案是,則寫多一個invalid_words_en,然後進行二次過濾,這樣處理後,就完全把這兩個英文過濾了;
JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

關於頻次的講解,大致就到這裡;

接下來是介紹頻率的統計,就是百分比,這個是通過jieba庫裡的analyse模組解決,支援直接讀取檔案過濾,即把不想要的分詞丟在一個檔案裡,然後會自動過濾,函式是:extract_tags
jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())

  • sentence 為待提取的文字

  • topK 為返回幾個 TF/IDF 權重最大的關鍵詞,預設值為 20,簡單理解就是提取多少個

  • withWeight 為是否一併返回關鍵詞權重值,預設值為 False

  • allowPOS 僅包括指定詞性的詞,預設值為空,即不篩選

    invalid_words_file = "invalidwords.txt"

    #設定停用詞 jieba.analyse.set_stop_words(invalid_words_file)

    #獲取關鍵詞頻率 tags = jieba.analyse.extract_tags(qzgs_text,topK=100,withWeight=True) for tag in tags: print(tag) 輸出的結果:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)
這裡也有不少無效的內容,懶得新增了;

到這裡,分詞跟詞頻都瞭解到了,接下來,看詞雲吧~

2 詞雲

網上找了下詞雲的庫,基本都用wordcloud,那我們也跟著用這個吧;

  • GitHub倉庫:https://github.com/amueller/word_cloud
  • 官方文件:https://amueller.github.io/word_cloud/
  • 一個比較詳細的教程:https://blog.csdn.net/fontthrone/article/details/72775865

pip安裝一波:

pip install wordcloud
複製程式碼

但是JB在安裝的時候報錯了;

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

然後改用另外一種解決方案了,開啟下面的連結:

http://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud 直接搜尋wordcloud,JB用的是Windows系統,所以選擇下載這個: wordcloud-1.4.1-cp36-cp36m-win_amd64.whl

下載後,直接執行,問題解決;(折騰一個小時了,坑~)

pip install wordcloud-1.4.1-cp36-cp36m-win_amd64.whl
複製程式碼

這個庫的使用,關鍵在於WordCloud建構函式

def __init__(self, font_path=None, width=400, height=200, margin=2,
             ranks_only=None, prefer_horizontal=.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=.5, regexp=None, collocations=True,
             colormap=None, normalize_plurals=True):
複製程式碼

引數講解:

  • font_path:字型路徑,就是繪製詞雲用的字型,比如monaco.ttf
  • width:輸出的畫布寬度,預設400畫素
  • height:輸出的畫布寬度,預設200畫素
  • margin:畫布偏移,預設2畫素
  • prefer_horizontal : 詞語水平方向排版出現的頻率,預設0.9,垂直方向出現概率0.1
  • mask:如果引數為空,則使用二維遮罩繪製詞雲。如果 mask 非空,設定的寬高值將 被忽略,遮罩形狀被 mask,除全白(#FFFFFF)的部分將不會繪製,其餘部分會用於繪製詞雲。 如:bg_pic = imread('讀取一張圖片.png'),背景圖片的畫布一定要設定為白色(#FFFFFF), 然後顯示的形狀為不是白色的其他顏色。可以用ps工具將自己要顯示的形狀複製到一個純白色 的畫布上再儲存,就ok了。
  • scale:按照比例進行放大畫布,如設定為1.5,則長和寬都是原來畫布的1.5倍
  • color_func:生成新顏色的函式,如果為空,則使用 self.color_func
  • max_words:顯示的詞的最大個數
  • min_font_size:顯示的最小字型大小
  • stopwords:需要遮蔽的詞(字串集合),為空使用內建STOPWORDS
  • random_state:如果給出了一個隨機物件,用作生成一個隨機數
  • background_color:背景顏色,預設為黑色
  • max_font_size:顯示的最大的字型大小
  • font_step:字型步長,如果步長大於1,會加快運算但是可能導致結果出現較大的誤差
  • mode:當引數為"RGBA",並且background_color不為空時,背景為透明。預設RGB
  • relative_scaling:詞頻和字型大小的關聯性,預設5
  • regexp:使用正規表示式分隔輸入的文字
  • collocations:是否包括兩個詞的搭配
  • colormap:給每個單詞隨機分配顏色,若指定color_func,則忽略該方法
  • normalize_plurals:是否刪除尾隨的詞語

常用的方法:

  • fit_words(frequencies) //根據詞頻生成詞雲
  • generate(text) //根據文字生成詞雲
  • generate_from_frequencies(frequencies[, ...]) #根據詞頻生成詞雲
  • generate_from_text(text) #根據文字生成詞雲
  • process_text(text) #將長文字分詞並去除遮蔽詞 (此處指英語,中文分詞還是需要自己用別的庫先行實現,使用上面的 fit_words(frequencies) )
  • recolor([random_state, color_func, colormap]) #對現有輸出重新著色。重新上色會比重新生成整個詞雲快很多。
  • to_array() #轉化為 numpy array
  • to_file(filename) #輸出到檔案

看完後賊難受的,而且真沒多少記得,懵逼吧,先從簡單的例子入手吧:

from wordcloud import WordCloud

data = "所有人,看起來,說網,不是,什麼"

wc= WordCloud(background_color="white")
wc = wc.generate(data)
wc.to_file("111.jpg")
複製程式碼

程式碼能執行,執行的效果是這樣的:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

看上去,好像是沒有字型導致的,加個字型試試,因為JB是用WINDOWS,直接那系統的字型了;

data = "所有人,看起來,說網,不是,什麼"

wc= WordCloud(background_color="white",font_path="C:/Windows/Fonts/STFANGSO.ttf")
wc = wc.generate(data)
wc.to_file("111.jpg")
複製程式碼

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

ok,現在可以了~
有個效率的問題,現在是每次儲存到111.jpg,然後手動開啟,這個過程雖然不麻煩,但是次數一到就覺得厭倦了,那能否自動彈出圖片?答案是有的,需要matplotlib.pyplot這個庫:

from wordcloud import WordCloud,
import matplotlib.pyplot as plt

data = "所有人,看起來,說網,不是,什麼"
wc= WordCloud(background_color="white",font_path="C:/Windows/Fonts/STFANGSO.ttf")
wc = wc.generate(data)

#顯示詞雲圖片
plt.imshow(wc)
plt.show()

#儲存圖片
wc.to_file("111.jpg")
複製程式碼

修改成這樣後,執行後就自動彈出圖片了,圖片長這樣的:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

居然帶有座標,這多醜啊,怎麼去除?

#顯示詞雲圖片
plt.imshow(wc)
plt.axis("off")
#axis函式接收一個list,設定橫縱座標尺度,list各個引數分別代表[X初始刻度,X終止刻度,Y起始刻度,Y終止,off就是不顯示座標尺寸
plt.show()
複製程式碼

只需要加上plt.axis("off")即可:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

但是網上看到別人的是這樣的,為啥我們的差距那麼大?

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

那我們也來找一張圖片,如下(正經圖正經圖):

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

然後改一波程式碼把:

#data自己定義哈,為了顯示效果,用盡可能多的資料了

#字型路徑
path = "C:/Windows/Fonts/STFANGSO.ttf"

#讀入背景圖片,就是上面那張圖片
bg_pic = imread("11.jpg")     

wc= WordCloud(background_color="white",font_path=path,mask=bg_pic)
wc = wc.generate(data)

#顯示詞雲圖片
plt.imshow(wc)
plt.axis("off")
#axis函式接收一個list,設定橫縱座標尺度,list各個引數分別代表[X初始刻度,X終止刻度,Y起始刻度,Y終止,off就是不顯示座標尺寸
plt.show()

#儲存圖片
wc.to_file("111.jpg")
複製程式碼

效果如下:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

整體效果出來了,這字型顏色貌似是隨機的,要不讓字型跟隨著圖片顏色變化?

#讀入背景圖片
bg_pic = imread("11.jpg")
#從背景圖片生成顏色值
image_colors = ImageColorGenerator(bg_pic)

wc= WordCloud(background_color="black",font_path=path,mask=bg_pic,color_func=image_colors)
複製程式碼

結果是這樣的:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

尼瑪,忘記圖片大部分是白色的。。那把背景改黑色吧:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

剩下的,就是怎選圖跟選用字型以後一些引數細節,這塊不打算詳細說了,也不想糾結了,大致知道用法即可;

把整體程式碼封裝下,最後程式碼如下:

import re
import jieba.analyse
from collections import Counter
from wordcloud import WordCloud, ImageColorGenerator,STOPWORDS
import matplotlib.pyplot as plt
from scipy.misc import imread

#這個檔案是統計頻率時,把需要過濾的詞放到這個檔案裡面
#invalid_words_file = "invalidwords.txt"


def get_Words():
    #讀取TXT檔案獲取文字里的內容
    with open("quanzhigaoshou.txt", encoding='utf-8') as f:
        qzgs_text = f.read()
    #制定正則規則,把各種符號去掉,最後生成沒有各種符號的字串
    pattern = re.compile('[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?“”、~@#¥%……&*()(\d+)]+')
    new_qzgs_text = pattern.sub("", qzgs_text)

    #獲取分詞
    qzgs_words = [word for word in jieba.cut(new_qzgs_text, cut_all=False) if len(word) > 2]

    # #設定停用詞
    # jieba.analyse.set_stop_words(invalid_words_file)
    #
    # #獲取關鍵詞頻率
    # tags = jieba.analyse.extract_tags(qzgs_text,topK=100,withWeight=True)
    # for tag in tags:
    #     print(tag)

    #制定需要過濾的詞
    invalid_words_zh = ["所有人", "看起來", "小說網", "是不是", "為什麼", "沒什麼", "其他人", "未完待續",
                        "事實上", "一時間", "是因為", "一瞬間", "只不過", "差不多", "不至於", "這時候", "越來越", "沒想到", "可不是", "不得不", "接下來",
                        "魄之力", "俱樂部", "挑戰賽", "全明星", "擂臺賽", "季後賽","boss", "wwwmianhuatangla"]

    #進行過濾操作
    for word in qzgs_words:
        if word in invalid_words_zh:
            qzgs_words.remove(word)

    # 獲取分詞頻數
    # c = Counter(qzgs_words)
    # for word in c.most_common(50):
    #     word,freq = word
    #     print(word,freq)

    #空格分隔下
    data = r" ".join(qzgs_words)
    return data

def generate_wc(data):
    # 字型路徑
    path = "C:/Windows/Fonts/STFANGSO.ttf"
    # 讀入背景圖片
    bg_pic = imread("bjt.jpg")
    # 從背景圖片生成顏色值
    image_colors = ImageColorGenerator(bg_pic)
    # 生成詞雲,後面的generate是根據文字生成詞雲
    wc = WordCloud(background_color="black", font_path=path, mask=bg_pic, color_func=image_colors)
    wc = wc.generate(data)
    # 顯示詞雲圖片
    plt.imshow(wc)
    plt.axis("off")
    # axis函式接收一個list,設定橫縱座標尺度,list各個引數分別代表[X初始刻度,X終止刻度,Y起始刻度,Y終止,off就是不顯示座標尺寸
    plt.show()
    # 儲存圖片
    wc.to_file("result.jpg")


if __name__ =="__main__":
    data=get_Words()
    generate_wc(data)
複製程式碼

底圖一換,就成這樣:

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

挑個好字型跟好顏色,估計更好看,這字型太模糊了=。=

小結

雖然做的比較醜,但算是達到目的了,折騰了不少時間,主要還是在環境搭建那塊,當然看資料也算,雖然網上很多教程,但大部分都是直接扔一堆程式碼過來的,連註釋都比較少,對於新同學不是很友好;
本文通過實戰圍繞介紹使用jieba庫進行中文分詞,並使用collections模組進行分詞的次數統計,介紹了wordcloud詞雲庫的使用方式;

雜七雜八

中文分詞,用jieba,那英文分詞呢?
有NLTK,基本邏輯跟中文分詞類似:

  • 讀取檔案->過濾特殊符號->分詞->詞形還原->統計詞頻->詞雲
    詞形還原什麼鬼,簡單看了下,沒太懂,大致有個庫能通過是過去式還是進行時來還原部分詞,大致是這樣;

好了,本章介紹了,下章會結合爬取拉鉤等招聘網站,來介紹numpy,pandas和matplotlib進行資料分析;

謝謝大家!~

JB的Python之旅-資料分析篇-jieba&wordcloud(詞雲)

相關文章