利用Python分析庆余年角色出现情况

大家在抖音,头条上都见过那种随着时间变化,排位不断变化的柱形动态图,比如全世界各国高铁总里程伴随年份增长的那种。最近庆余年大火,然后想到能不能用python把整本书中大部分的人物给抓出来,然后分析一下,随着情节的发展,这些人出现的状况是个什么样子。

废话不多说,我们开始,思路大概是这样的:

1. 如何实现动态柱状图?

经过查询,发现GitHub上的这个模板:
https://github.com/Jannchie/Historical-ranking-data-visualization-based-on-d3.js
此模板用起来特别方便,如果没有特别的要求的话,把数据加载进去就能用,使用的数据格式为csv, 结构为:

name,type,value,date
name1, type1, 12000, 2013-12-31
name2, type2, 10000, 2013-12-31
name3, type3, 10000, 2013-12-31
name1, type1, 12300, 2014-12-31
name2, type1, 12040, 2014-12-31
name3, type1, 12001, 2014-12-31

OK,那我们需要的格式就应该为
name, type, value, page
其中,name为角色名称,type根据作者说,是变化颜色的,我们这里面就给他一个简介的含义,value和page比较麻烦,我们细说:
page - 庆余年全书大概有三百八十万以上的字数,这样我们按照36000字分一页,大概能分出100页左右。那么value就是截止到此页,该人物一共出现了多少次。
这个概念弄懂了,那么我们的程序最后应该生成的数据大概长这样:

name,type,value,date
叶流云,南庆大宗师父,10,1
陈萍萍,监察院长,6,1
苦荷,北齐大宗师,6,1
太子,太子,4,1
范闲,本书男主,249,1
影子,陈萍萍护卫,1,1
皇帝,书中皇帝,26,1
范建,主角他爹,53,1
范若若,范闲妹妹,2,1
范建,主角他爹,98,2
叶流云,南庆大宗室,12,2
柳思思,范闲妾,18,2
洪四庠,太后太监,2,2
影子,陈萍萍护卫,3,2

OK搞懂了我们继续

2 开始分词

在这里我们使用 结巴分词
jieba里面有个方法

jieba.tokenize(text)

这个方法会把每一个分出来的词,在文章中出现的位置,结束的位置都返回来,这样的话,通过每个分出来的人在文章中出现的启示位置就可以知道这个人出现在“按照36000字分一页”这个分法的第几页。
好好理解这句话,然后我们上代码。这里需要注意的是:

  1. 我们加载了一个字典,这个字典是干啥用的呢?就是定义了我们想要看到的人名,除了这些人以外其他分出来的词就不要了,免得什么小太监,士兵甲乙丙,宫女子丑寅都进来。
  2. 我们将最后分出来的词,以字典的方式存到一个列表中,最后这个列表会用pandas生成dataframe进行下一步操作
# 定义分页方法
def page_generate(book, wordsPerPage):
    page_list = []
    n = 0
    for i in range(0, len(book), wordsPerPage):
        n = n+1
        pageInfo = {
            'page_number':n,
            'start':i,
            'end':i+wordsPerPage
        }
        page_list.append(pageInfo)
    return page_list

# 定义分词方法
def get_words_details(text, dict_url):
    jieba.load_userdict(dict_url)
    results = jieba.tokenize(text)
    final_info = []
    for result in results:
        name = result[0]
        location = result[1]
        pagenumber = 0
        for subpage in page_list:
            if location >= subpage['start'] and location <= subpage['end']:
                pagenumber = subpage['page_number']
        worddetail = {
            'name':name,
            'location':location,
            'page': pagenumber
        }
        final_info.append(worddetail)
    return final_info

3 主程序

# 定义书路径
bookurl = 'C:\\Users\\zhigang.zhang\\Downloads\\qyn.txt'
# 定义字典路径
dict_url = 'C:\\Users\\zhigang.zhang\\Documents\\Python Scripts\\dict.txt'
# 打开书,读取内容为str
file = open(bookurl, 'r')
text = file.read()
# 生成每100个字为一页的页面信息,包含每一页第一个字和最后一个字在整本书里面的位置
page_list = page_generate(text, 36000)
# subtext_list = cut_book(text, 100)

#利用jieba分词进行分词,读取自定义字典提高分词精确性
print('分词开始')
final_info = get_words_details(text, dict_url)
print('分词结束')
# 将分此后每个词出现的位置读取成list
print('分页统计开始')
l = [final_info[i]['location'] for i in range(0, len(final_info))]
print('分页统计结束')
# 生成pandas dataframe, index为每个词出现位置
df = pd.DataFrame(final_info, index = l) 
print('生成dataframe')
#读取用户字典里人名, 生成list,将分词后的数据进行过滤,只保留字典中存储的人名数据
file2 = open(dict_url, 'r')
role_list = file2.read().splitlines()
df2 = df[df['name'].isin(role_list)]

好的,到这里以你多年print('hello world')的功力,基本都能看懂了。需要注意的是最后两行:
我们过滤出 只有用户字典里面定义的 人物

然后是比较关键的两步

  1. 如果我们的字典里只是单纯包含了范闲,五竹,那就会漏掉很多关键的同义词,因此我们再创建一个字典,把提司大人,小范大人,这样的词都替换成范闲,老五,五大人,瞎子这样的词也都替换成五竹,这样的话得到的数据会更加精确(不要杠精,我这个也不是都准)
#部分字典内容
nickname = {'范慎':'范闲',
'提司大人':'范闲',
'范提司':'范闲',
'小范大人':'范闲',
'澹泊公':'范闲',
'庆帝':'皇帝',
'寡人':'皇帝',
'朕':'皇帝',
'陛下':'皇帝',
'户部尚书':'范建',
'户部侍郎':'范建',
'司南伯':'范建',
'伯爵':'范建',
'范侍郎':'范建',
'范尚书':'范建',
'五大人':'五竹',
'老五':'五竹',
'瞎子':'五竹',
'院长':'陈萍萍',
'跛子':'陈萍萍',
...
}
  1. 定义一个给dataframe 依据name列的值,赋予不同type值的方法。为啥要用一个方法?因为我们要用lamda,往后看
def get_type(x):
    dic = {'范闲':'本书男主',
'叶轻眉':'主角母亲',
'皇帝':'书中皇帝',
'范建':'主角他爹',
'五竹':'机器人',
'陈萍萍':'监察院长',
'靖王':'王爷',
'李云睿':'长公主',
'林若甫':'范闲岳父',
...}
    return dic.get(x)# x是key值,return一个对应的value出去

然后我们开始替换,利用dataframe的replace功能

df3 = df2.replace(nickname)
#按照name,page,对于出现次数进行统计
df4 = df3.groupby(['name', 'page']).count()
#dataframe进行group by之后,index发生改变,进行重设并重命名
df4.reset_index(inplace=True)
df5 = df4.rename(columns={'location':'numberOfAppearance'})
#################################################################
#新增一列,名为 totalAppear, 意为截至此页,这个人物 累计 出现多少次#
#################################################################
df5['totalAppear'] = df5.groupby(['name'])['numberOfAppearance'].cumsum()

#根据name列的值,新增type列并赋值
df5['type'] = df5['name'].apply(lambda x: get_type(x))
#因为只需要累加,所以去掉num of Apperaance 列
df5.drop(['numberOfAppearance'], axis=1)

#因为那个js工具只只支持标准顺序,所以我们把df的字段顺序调整一下,然后根据page字段排序,从小到大排列
order = ['name', 'type', 'totalAppear', 'page']
df6 = df5[order].sort_values(by = 'page')

#这个地方想实验一下重命名,就没有在js的那个config文件配置而是直接改df的字段名,所以最终字段名比较诡异
df7 = df6.rename(columns={'totalAppear':'value', 'page':'date'})

df7.to_csv('C:\\Users\\xxxxxx\\Downloads\\data.csv', index = False)
print('done')

好的,至此我们代码完成,10m多的庆余年加载进去,大概也就1,2分钟就能出来最终的csv文件

然后我们打开那个动态柱状图工具,把csv加载进去
最终结果在此
https://www.ixigua.com/i6774988371577012740/
通过本次分析,我们能够大概得出几个初步结论:

  1. 在整本书的前半部分,最关心范闲的是 皇帝,五竹,范建,他们几个在前十几页基本处于柱状图最上面
  2. 五竹的确是神龙见首不见尾,一会消失,一会又出现。
  3. 北齐圣女出现的次数,频率跟正房林婉儿差不多,难道这俩也是真爱?
  4. 究竟是谁和谁和谁们配范闲走到了最后?在整书的最后几万字里面,皇帝在那(就不剧透了), 院长在那(也不剧透了), 海棠朵朵力压林婉儿,五竹也在,捧哏王启年还在。


    最后一页

    好了,还有更多的结论,你们自己研究吧。
    所有代码我一会都放GitHub,什么时候更新上来看看再说了

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

推荐阅读更多精彩内容