一句話概括
本文通過實戰圍繞介紹使用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))
複製程式碼
結果直接執行,報錯了
沒毛病,編碼問題,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進行資料分析;
謝謝大家!~