三国人物出场词频统计

忽然想知道三国中到底谁是主角,简单使用 Python 分析一下看看。最后画一个词云展示结论。

首先导入必要的包:

import jieba
from collections import Counter
from wordcloud import WordCloud

然后导入需要的电子版三国,储存在 txt 对象中,但是如果直接这样调用的话十分占用内存,我们采用一个可迭代对象分次导入。

关于这方面的说明详见:https://www.jianshu.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 话说天下大势分久必合合久必分。周末七国分争并入于秦。及秦灭之后楚、汉分争又并入于汉。汉朝自高祖斩白蛇而起义一统天下后来光武中兴传至献帝遂分为三国。推其致乱之由殆始于桓、灵二帝。桓帝禁锢善类崇信宦官。及桓帝崩灵帝即位大将军窦武、太傅陈蕃共相辅佐。

导入没问题,接下来是使用jieba.lcut()函数,将字符串分割成等量的中文词语。下面插播一条广告:

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.





['我', '来到', '北京', '清华大学']

从上面的例子可以看到输入一个字符串,返回了一个等量的中文词汇列表。

回到正题,知道了这个函数的用法,我们来看看怎么把我们的这本《三国》全部分词,并将全部词汇列表命名为: 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并不是报错他是可迭代对象全部迭代完成的标志。接下来我们需要统计一下每个词出现的频率,因为是一个词对应一个频率,那么我们选择内置数据结构字典来储存。

但是分词十分多,因为我们要统计人名出现的次数,所以我们其实只需要统计有两个字或三个字的词语即可。

# 创建空字典
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是“曹操”(曹操一定会是主角!!!)那么这一步就应该是:

counts['曹操'] = counts.get('曹操', 0) + 1

dic.get('key', 默认值)是一个字典函数,它的作用是确定字典中是否存在某个 key 并获取其 value,如果没找到这个 key 就返回默认值。详见:https://www.jianshu.com/p/5d0bef1bc259

那么程序在执行这一步的时候会在字典 counts 中寻找 key 值为‘曹操’的键值对,如果找到了把 value 加一,并更新 value。


我们赶快看看到底是谁出现的次数比较多:

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('云长')

我们看一下现在的 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)]

从上面的输出中可以看出有很多无关的词汇,真的我忍他们很久了!!是时候对他们下手了!!!
首先创建一个无关词字典,值得注意的是,我们整合后的词也成了无关词就没有必要再次计算了,还有就是我们的目标是统计前 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

好吧,恭喜孔明,玄德君成功反超。

再次插播多条广告:

  • 统计出现频次最高的前20个词方法2
roles = Counter(counts)
role = roles.most_common(10)
print(role)
[('孔明', 1202), ('玄德', 1157), ('曹操', 909), ('张飞', 339), ('吕布', 258), ('孙权', 258), ('赵云', 254), ('云长', 239), ('司马懿', 221), ('周瑜', 215)]

这是使用collections中的Counter()函数,这个我还没有仔细研究,详细资料见http://www.pythoner.com/205.html

  • 注意items.sort(key=lambda x: x[1], reverse=True)中的 lambda 函数的使用
a = (1,2)
a[1]
2

广告插播结束,好啦到现在基本上我们就分析的差不多啦,但是这样的结果还是有点不直观,我们来试试画一个词云:

# 构造词云字符串
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('三国中出现前十的人物.png')
词云图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351