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

一句話歸納

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

前言

爬蟲獲取數據後,就須要數據分析了,那數據怎麼處理?用到什麼數據?一塊兒來看看吧~git

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

1 數據準備:

直接網上找全職高手txt下載,一大堆,解壓後獲取到txt文件;
全職高手txt小說下載地址正則表達式

1.2 讀取全職高手文本

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

結果直接執行,報錯了 dom

沒毛病,編碼問題,open時指定下utf-8便可:

看了下,整個文本的長度有 8623554 個字節,數據量很是可觀,感受題材會很豐富的~

這是否是就準備好了呢?
答案是NO,由於文本內容是這樣的:函數

從上圖能夠看出,文本里面會有各類符號跟廣告,目前這步,要作的就是把各類標點符號幹掉先;工具

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)
複製代碼

到此,字符串搞定啦~字體

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
複製代碼

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

官方提供的特色:

  • 支持三種分詞模式:
    • 精確模式,試圖將句子最精確地切開,適合文本分析;
    • 全模式,把句子中全部的能夠成詞的詞語都掃描出來,速度很是快,可是不能解決歧義;
    • 搜索引擎模式,在精確模式的基礎上,對長詞再次切分,提升召回率,適合用於搜索引擎分詞。

這裏貼一個官方的例子:

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把分詞遍歷下:

沒毛病,繼續;

接下來就是統計同詞詞頻,通常來講,會統計詞出現的次數,也叫頻次;

這塊,有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 輸出的結果:

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

invalid_words = ["全部人","看起來","小說網","wwwmianhuatangla","是否是","爲何","沒什麼","其餘人","未完待續",
                "事實上","一時間","是由於","一瞬間","只不過","差很少","不至於","這時候","愈來愈","沒想到","可不是","不得不","接下來",
                 "魄之力","俱樂部"]

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

輸出是這樣的:

不知道爲何,wwwmianhuatangla這玩意仍是一直存在,連boss都有,只是次數有所降低了,而臨時方案是,則寫多一個invalid_words_en,而後進行二次過濾,這樣處理後,就徹底把這兩個英文過濾了;

關於頻次的講解,大體就到這裏;

接下來是介紹頻率的統計,就是百分比,這個是經過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) 輸出的結果:

這裏也有很多無效的內容,懶得添加了;

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

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在安裝的時候報錯了;

而後改用另一種解決方案了,打開下面的連接:

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是用WINDOWS,直接那系統的字體了;

data = "全部人,看起來,說網,不是,什麼"

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

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")
複製代碼

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

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

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

只須要加上plt.axis("off")便可:

可是網上看到別人的是這樣的,爲啥咱們的差距那麼大?

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

而後改一波代碼把:

#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")
複製代碼

效果以下:

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

#讀入背景圖片
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)
複製代碼

結果是這樣的:

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

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

把總體代碼封裝下,最後代碼以下:

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)
複製代碼

底圖一換,就成這樣:

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

小結

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

雜七雜八

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

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

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

謝謝你們!~

相關文章
相關標籤/搜索