忽然想知道三國中到底誰是主角达椰,簡單使用 Python 分析一下看看项乒。最后畫一個詞云展示結論。
首先導入必要的包:
import jieba
from collections import Counter
from wordcloud import WordCloud
然后導入需要的電子版三國蝇裤,儲存在 txt 對象中频鉴,但是如果直接這樣調用的話十分占用內(nèi)存,我們采用一個可迭代對象分次導入垛孔。
關于這方面的說明詳見:http://www.reibang.com/p/968550b63f34
# 直接導入
with open('threekingdom.txt' ,'r', encoding='utf-8') as f:
txt = f.read()
# 使用可迭代對象分次導入
def read_file(fpath):
BLOCK_SIZE = 1024
with open(fpath, 'r', encoding='utf-8') as f:
while True:
block = f.read(BLOCK_SIZE)
if block:
yield block
else:
return
txt = read_file('threekingdom.txt')
我先檢查一下是否導入成功
txt.__next__()
這個輸出還是很多截取了部分在這里:
'\n------------\n\n正文\n\n\n------------\n\n第一回 宴桃園豪杰三結義 斬黃巾英雄首立功\n\n 滾滾長江東逝水浪花淘盡英雄似炎。是非成敗轉頭空辛萍。\n\n 青山依舊在幾度夕陽紅。\u3000\u3000白漁樵江渚上慣\n\n 看秋月春風贩毕。一壺濁酒喜相逢仆嗦。古今多少事都付\n\n 笑談中。\n\n ——調寄《臨江仙》\n\n 話說天下大勢分久必合合久必分瘩扼。周末七國分爭并入于秦。及秦滅之后楚规辱、漢分爭又并入于漢栽燕。漢朝自高祖斬白蛇而起義一統(tǒng)天下后來光武中興傳至獻帝遂分為三國。推其致亂之由殆始于桓碍岔、靈二帝∮芘Γ桓帝禁錮善類崇信宦官。及桓帝崩靈帝即位大將軍竇武奈籽、太傅陳蕃共相輔佐。
導入沒問題爆捞,接下來是使用jieba.lcut()
函數(shù)勾拉,將字符串分割成等量的中文詞語。下面插播一條廣告:
txt1 = '我來到北京清華大學'
setlist = jieba.lcut(txt1)
setlist
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\AppData\Local\Temp\jieba.cache
Loading model cost 1.719 seconds.
Prefix dict has been built succesfully.
['我', '來到', '北京', '清華大學']
從上面的例子可以看到輸入一個字符串藕赞,返回了一個等量的中文詞匯列表。
回到正題双霍,知道了這個函數(shù)的用法批销,我們來看看怎么把我們的這本《三國》全部分詞,并將全部詞匯列表命名為: world
均芽。
words = []
while True:
words += jieba.lcut(txt.__next__())
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\AppData\Local\Temp\jieba.cache
Loading model cost 1.654 seconds.
Prefix dict has been built succesfully.
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-3-9c577e6b04b4> in <module>
1 words = []
2 while True:
----> 3 words += jieba.lcut(txt.__next__())
StopIteration:
上面的StopIteration
并不是報錯他是可迭代對象全部迭代完成的標志。接下來我們需要統(tǒng)計一下每個詞出現(xiàn)的頻率深纲,因為是一個詞對應一個頻率劲妙,那么我們選擇內(nèi)置數(shù)據(jù)結構字典來儲存。
但是分詞十分多镣奋,因為我們要統(tǒng)計人名出現(xiàn)的次數(shù),所以我們其實只需要統(tǒng)計有兩個字或三個字的詞語即可富雅。
# 創(chuàng)建空字典
counts = {}
# 遍歷字典
for word in words:
if len(word) == 1:
continue
else:
# 往字典里增加元素
counts[word] =counts.get(word, 0) + 1
# print(counts)
這個輸出也有點多肛搬,大概類似于這種:
{'正文': 1, '第一回': 1, '桃園': 19, '豪杰': 22, '結義': 14, '黃巾': 40, '英雄': 82, '立功': 22, '滾滾': 5, '長江': 25, '逝水': 1, '浪花': 1, '淘盡': 1, '是非成敗': 1, '轉頭': 2, '青山': 1, '依舊': 11, '幾度': 1, '夕...
這里面的'向子典里增加元素'是很巧妙的一步毕贼,我來解釋一下這步:
counts[word] =counts.get(word, 0) + 1
其實這個語句是比較復雜的counts['key'] = value
, 舉一個栗子,如果此時的word
是“曹操”(曹操一定會是主角9硌ⅰF》贰0菅怼)那么這一步就應該是:
counts['曹操'] = counts.get('曹操', 0) + 1
dic.get('key', 默認值)
是一個字典函數(shù),它的作用是確定字典中是否存在某個 key 并獲取其 value志衍,如果沒找到這個 key 就返回默認值聊替。詳見:http://www.reibang.com/p/5d0bef1bc259
那么程序在執(zhí)行這一步的時候會在字典 counts 中尋找 key 值為‘曹操’的鍵值對,如果找到了把 value 加一惹悄,并更新 value。
我們趕快看看到底是誰出現(xiàn)的次數(shù)比較多:
items = list(counts.items())
items.sort(key=lambda x: x[1], reverse=True)
items
輸出大概類似于這種:[('曹操', 909),('孔明', 817),('將軍', 740),('卻說', 642),('玄德', 514),('關公', 507),('丞相', 483),('二人', 457),('不可', 427)('荊州', 419),('孔明曰', 385) ('不能', 380),('如此', 376),('玄德曰', 375),('商議', 341),('張飛', 339),('如何', 332),('主公', 326),('軍士', 307),('左右', 288),('軍馬', 288),('劉備', 268),('次日', 267),('引兵', 265),('大喜', 263),('呂布', 258),('孫權', 258),...
哈哈哈哈果然是曹操老哥暂殖,曹操老哥牛X当纱!等等先不要高興太早,這里面其實還有像‘劉備’惫东,‘玄德’,‘玄德曰’其實都是‘劉備’這個人颓遏,好的本著公平公正的原則就把他們都整合到一起吧滞时。
counts['孔明'] = counts.get('孔明') + counts.get('孔明曰')
counts['玄德'] = counts.get('玄德曰') + counts.get('玄德')
counts['玄德'] = counts.get('玄德') + counts.get('劉備')
counts['關公'] = counts.get('關公') + counts.get('云長')
我們看一下現(xiàn)在的 top 20是啥樣:
items[0:20]
輸出為[('曹操', 909),('孔明', 817),('將軍', 740),('卻說', 642),('玄德', 514),('關公', 507),('丞相', 483),('二人', 457),('不可', 427),('荊州', 419),
('孔明曰', 385),('不能', 380),('如此', 376),('玄德曰', 375),('商議', 341),('張飛', 339),('如何', 332),('主公', 326),('軍士', 307),('左右', 288)]
從上面的輸出中可以看出有很多無關的詞匯,真的我忍他們很久了B妗窒百!是時候對他們下手了!8萆摇!
首先創(chuàng)建一個無關詞字典,值得注意的是榴嗅,我們整合后的詞也成了無關詞就沒有必要再次計算了陶舞,還有就是我們的目標是統(tǒng)計前 10 的人物,所以不需要獲得全部的無關詞肿孵。
excludes = {"將軍", "卻說", "丞相", "二人", "不可", "荊州", "不能", "如此", "商議",
"如何", "主公", "軍士", "軍馬", "左右", "次日", "引兵", "大喜", "天下",
"東吳", "于是", "今日", "不敢", "魏兵", "陛下", "都督", "人馬", "不知",
'玄德曰', '孔明曰', '劉備', '關公'}
for word in excludes:
del counts[word]
我們重新排序來看看處理后的結果
items = list(counts.items()) # 將字典轉化為 元組的字典
items.sort(key=lambda x: x[1], reverse=True)
print(items[0:10])
[('孔明', 1202), ('玄德', 1157), ('曹操', 909), ('張飛', 339), ('呂布', 258), ('孫權', 258), ('趙云', 254), ('云長', 239), ('司馬懿', 221), ('周瑜', 215)]
items.sort(key=lambda x: x[1], reverse=True)
for i in range(10):
character, count= items[i] # 這是一個拆包操作
print(character, count)
孔明 1202
玄德 1157
曹操 909
張飛 339
呂布 258
孫權 258
趙云 254
云長 239
司馬懿 221
周瑜 215
好吧颁井,恭喜孔明,玄德君成功反超雅宾。
再次插播多條廣告:
- 統(tǒng)計出現(xiàn)頻次最高的前20個詞方法2
roles = Counter(counts)
role = roles.most_common(10)
print(role)
[('孔明', 1202), ('玄德', 1157), ('曹操', 909), ('張飛', 339), ('呂布', 258), ('孫權', 258), ('趙云', 254), ('云長', 239), ('司馬懿', 221), ('周瑜', 215)]
這是使用collections
中的Counter()
函數(shù),這個我還沒有仔細研究贯吓,詳細資料見http://www.pythoner.com/205.html
- 注意
items.sort(key=lambda x: x[1], reverse=True)
中的 lambda 函數(shù)的使用
a = (1,2)
a[1]
2
廣告插播結束蜀变,好啦到現(xiàn)在基本上我們就分析的差不多啦,但是這樣的結果還是有點不直觀库北,我們來試試畫一個詞云:
# 構造詞云字符串
li = []
for i in range(10):
character, count = items[i]
for _ in range(count):
li.append(character)
# print(li)
cloud_txt = ",".join(li)
測試一下emmmmm這個的輸出誰用誰知道,情屹,杂腰,
# 構造詞云字符串
wc = WordCloud(
background_color='white', # 改變底色 默認為黑色
font_path='msyh.ttc',
# 是否包含兩個詞的搭配默認是True
collocations=False
).generate(cloud_txt)
wc.to_file('三國中出現(xiàn)前十的人物.png')