美文网首页
五王之战分析 - 冰与火之歌-Udacity

五王之战分析 - 冰与火之歌-Udacity

作者: 夏寒RHT | 来源:发表于2018-10-31 12:40 被阅读0次

    简介

    来源于Udacity数据分析试学项目。

    五王之战(War of the Five Kings)是著名严肃奇幻小说《冰与火之歌》中的著名内战。这是一场规模空前、波及七大王国的内乱。顾名思义,前后共有五人在战争中称王:乔佛里、史坦尼斯、蓝礼均声称自己是铁王座的合法继承人。除此之外,罗柏·史塔克被北境众封臣推选为北境之王,巴隆·葛雷乔伊亦再度掀起独立大旗,欲摆脱铁王座的统治,自称为铁群岛之王。

    本数据集(battles.csv)包含了五王之战期间的战争,它是所有战斗的大集合。该数据是Kaggle中Game of Thrones的一部分。

    数据中的变量含义解释:

    name: 战争的名称,字符变量。
    year: 战争发生的年份,数值变量。
    battle_number: 本数据中的unique id,对应每一场独立的战役,数值变量。
    attacker_king: 攻击方的国王,"/"表示了国王的更换。例如:"Joffrey/Tommen Baratheon"意味着Tomen Baratheon继承了Joffrey的王位,分类变量。
    defender_king: 防守方的国王,分类变量。
    attacker_1: 攻击方将领,字符变量。
    attacker_2: 攻击方将领,字符变量。
    attacker_3: 攻击方将领,字符变量。
    attacker_4: 攻击方将领,字符变量。
    defender_1: 防守方将领,字符变量。
    defender_2: 防守方将领,字符变量。
    defender_3: 防守方将领,字符变量。
    defender_4: 防守方将领,字符变量。
    attacker_outcome: 从攻击方角度来看的战争结果,分别有:win, loss, draw,分类变量。
    battle_type: 战争的类别。pitched_battle: 双方军队在一个地点相遇并战斗,这也是最基本的战争类别;ambush: 以隐身或诡计为主要攻击手段的战争;siege: 阵地战;razing: 对未设防位置的攻击。分类变量。
    major_death: 是否有重要人物的死亡,二进制变量。
    major_capture: 是否有重要人物的被捕,二进制变量。
    attacker_size: 攻击方力量的大小,并未对骑兵、步兵等士兵种类有所区分,数值变量。
    defender_size: 防守方力量的大小,并未对骑兵、步兵等士兵种类有所区分,数值变量。
    attacker_commander: 攻击方的主要指挥官。指挥官的名字中并没有包含头衔,不同的指挥官名字用逗号隔开,字符变量。
    defender_commander: 防守方的主要指挥官。指挥官的名字中并没有包含头衔,不同的指挥官名字用逗号隔开,字符变量。
    summer: 战争是否发生于夏天,二进制变量。
    location: 战争发生的地点,字符变量。
    region: 战争发生的地域,包括:Beyond the Wall, The North, The Iron Islands, The Riverlands, The Vale of Arryn, The Westerlands, The Crownlands, The Reach, The Stormlands, Dorne,分类变量。
    note: 注释,字符变量。
    
    

    提出问题

    在此项目中,你将以一名数据分析师的身份执行数据的探索性分析。你将了解数据分析过程的基本流程。在你分析数据之前,请先思考几个你需要理解的关于这些战斗的问题,例如,哪一个区域发生了最多的战争?哪一个国王获得了最多的胜利?战争的胜利与否受那些关键因素的影响?

    问题:请写下你感兴趣的问题,请确保这些问题能够由现有的数据进行回答。
    (为了确保学习的效果,请确保你的数据分析报告中能够包含2幅可视化和1个相关性分析。)

    我提出的问题:

    1.这些战役共涉及几位国王参战,各自参战的比例是多少?
    2.每个国王的胜率是多少?
    3.哪个国王更具侵略性?
    4.哪种战争类型最多,哪种胜率更高?
    5.除了几位国王势力,还有其他那些家族参与了战争,他们是哪位国王的联盟?
    6.所有战争前后经历了几年,每年的夏天的比例是多少?

    在提出了问题之后,我们将开始导入数据,并对数据进行探索性分析,来回答上面提出的问题。

    数据评估和清理

    # TO DO: load pacakges
    #coding=utf-8
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
    
    # TO DO: load the dataset
    got_df = pd.read_csv('battles.csv')
    
    got_df 
    

    Out[3]:由于移动端显示表格不理想,这里只放了原始数据的图片供参考


    # TO DO: check the dataset general info
    got_df.info()
    

    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 38 entries, 0 to 37
    Data columns (total 25 columns):
    name 38 non-null object
    year 38 non-null int64
    battle_number 38 non-null int64
    attacker_king 36 non-null object
    defender_king 35 non-null object
    attacker_1 38 non-null object
    attacker_2 10 non-null object
    attacker_3 3 non-null object
    attacker_4 2 non-null object
    defender_1 37 non-null object
    defender_2 2 non-null object
    defender_3 0 non-null float64
    defender_4 0 non-null float64
    attacker_outcome 37 non-null object
    battle_type 37 non-null object
    major_death 37 non-null float64
    major_capture 37 non-null float64
    attacker_size 24 non-null float64
    defender_size 19 non-null float64
    attacker_commander 37 non-null object
    defender_commander 28 non-null object
    summer 37 non-null float64
    location 37 non-null object
    region 38 non-null object
    note 5 non-null object
    dtypes: float64(7), int64(2), object(16)
    memory usage: 7.5+ KB

    可以看出,数据集中共收录了38场战役,defender3 4,无数据, note没有分析的意义,所以去掉这些字段。

    # TO DO: clean the data (optional: only there are problems)
    got_df.drop([ 'defender_3','defender_4', 'note'], axis=1, inplace=True)
    

    另外,本次数据分析主要针对五位国王进行分析,在数据集中,第23场战役和第30场战役均无对垒双方国王的信息,所以在这里删除这两场战役

    got_df.drop([22,29], axis=0, inplace=True)
    got_df
    got_df.info()
    

    <class 'pandas.core.frame.DataFrame'>
    Int64Index: 36 entries, 0 to 37
    Data columns (total 22 columns):
    name 36 non-null object
    year 36 non-null int64
    battle_number 36 non-null int64
    attacker_king 36 non-null object
    defender_king 35 non-null object
    attacker_1 36 non-null object
    attacker_2 10 non-null object
    attacker_3 3 non-null object
    attacker_4 2 non-null object
    defender_1 36 non-null object
    defender_2 2 non-null object
    attacker_outcome 35 non-null object
    battle_type 35 non-null object
    major_death 35 non-null float64
    major_capture 35 non-null float64
    attacker_size 24 non-null float64
    defender_size 19 non-null float64
    attacker_commander 36 non-null object
    defender_commander 28 non-null object
    summer 35 non-null float64
    location 36 non-null object
    region 36 non-null object
    dtypes: float64(5), int64(2), object(15)
    memory usage: 6.5+ KB

    数据探索分析

    1.这些战役共涉及几位国王参战,各自参战的比例是多少?

    # 攻击方国王
    attacker=got_df.groupby('attacker_king').size()
    # 防御方国王
    defender=got_df.groupby('defender_king').size()
    # 两者相加统计国王参战次数
    king_total= attacker.add(defender,fill_value=0)
    
    king_total
    

    Balon/Euron Greyjoy 11.0
    Joffrey/Tommen Baratheon 27.0
    Mance Rayder 1.0
    Renly Baratheon 1.0
    Robb Stark 24.0
    Stannis Baratheon 7.0
    dtype: float64

    # 绘制饼图
    king_total.plot.pie(labels=['Balon/Euron Greyjoy', 'Joffrey/Tommen Baratheon', 'Mance Rayder', 'Renly Baratheon', 'Robb Stark', 'Stannis Baratheon'], 
                                                 autopct='%.1f%%', fontsize=16, figsize=(6, 6),style = dict, title =u'参战国王')
    

    共有六位国王参与了战争,除了五王之外,Mance作为塞外之王带领长城以北的野人参与了黑城堡之战Battle of Castle Black,这里我也发现了数据集中的一个明显的错误,如下表,在Battle of Castle Black一战中,Mance Rayder应该是攻击一方,应该是attacker_king,而不应该是defender_king。根据右面的attacker_1字段是Free folk,以及attacker_commander字段包含Mance也可以看出来。不过这里依然保留原始数据,不再对数据做修正。

    作为七国国王,Joffrey参与了最多的战争,参战率为38.0%,紧随其后的是北境之王Robb,参战率为33.8%。

    Renly 仅参加了一场战斗Siege of Storm's End,就命丧于风息堡。

    2.每个国王的胜率是多少?

    # 攻击方获胜
    attacker_win = got_df[got_df['attacker_outcome'] == 'win'].groupby('attacker_king').size()
    # 防御方获胜
    defender_win = got_df[got_df['attacker_outcome'] == 'loss'].groupby('defender_king').size()
    # 总共胜利战役数量
    king_win = attacker_win.add(defender_win,fill_value=0)
    
    king_win
    

    Balon/Euron Greyjoy 7.0
    Joffrey/Tommen Baratheon 16.0
    Mance Rayder 1.0
    Robb Stark 9.0
    Stannis Baratheon 2.0
    dtype: float64

    # 胜率
    king_win.div(king_total,fill_value=0)
    

    Balon/Euron Greyjoy 0.636364
    Joffrey/Tommen Baratheon 0.592593
    Mance Rayder 1.000000
    Renly Baratheon 0.000000
    Robb Stark 0.375000
    Stannis Baratheon 0.285714
    dtype: float64

    # 柱状图
    king_win.div(king_total,fill_value=0).plot.bar(figsize=(6,5),fontsize=16,title = u'各王胜率')
    

    从柱状图可知,Mance仅参加一场战斗而且获胜,胜率最高,实际前面也提到,这条数据应该是错误的,实际Mance应该是战败方,所以并不具备参考价值。

    其余五王中,铁群岛Balond 的胜率最高为63.6%,铁民天生就是打架的材料;Joffrey依托君临城御林军和Lannister家族的强大实力,在参战次数最多的前提下,依然保持了较高的胜率;可怜的Renly仅参战一场并且失败,胜率为0最低,不过Stannis利用红袍女Melisandre的魔法将Renly杀死,的确也胜之不武;耿直的狼家Robb虽然参战次数不少,但胜率却不高,的确缺乏战略天赋。

    3.哪个国王更具侵略性?

    # 各王作为攻击方的次数柱状图
    attacker.plot.bar(figsize=(6,5),fontsize=16,title = u'各王攻击次数')
    

    从图中可以看出,Joffrey坐拥铁王座,成为了最具侵略性的国王。

    4.哪种战争类型最多,哪种胜率更高?

    # 战争类别统计
    battle_type=got_df.groupby('battle_type').size()
    battle_type.plot.pie(labels=['ambush', 'pitched battle', 'razing', 'siege'], 
                                                 autopct='%.1f%%', fontsize=16, figsize=(6, 6),style = dict, title =u'战争类别')
    

    可以看出,pitched battle比例最高。

    # 获胜的战争类别统计
    battle_type_win = got_df[got_df['attacker_outcome']== 'win'].groupby('battle_type').size()
    
    # 不同战争类别胜率
    battle_type_win.div(battle_type,fill_value=0)
    
    battle_type_win.div(battle_type,fill_value=0).plot.bar(figsize=(6,5),fontsize=16,title = u'不同战争类别胜率')
    

    可以看出,ambush 和 razing都保持了100%的胜率,但是razing的数量太小,不具备一般性,所以还是认为ambush的胜率最高。

    5.除了几位国王势力,还有其他那些家族参与了战争,他们是哪位国王的联盟?

    ## 从attacker_1 2 3 4和defender_1 2中提取所有的家族
    a1=got_df.groupby('attacker_1').size()
    a2=got_df.groupby('attacker_2').size()
    a3=got_df.groupby('attacker_3').size()
    a4=got_df.groupby('attacker_4').size()
    d1=got_df.groupby('defender_1').size()
    d2=got_df.groupby('defender_2').size()
    # 所有series相加
    a1.add(a2,fill_value=0).add(a3,fill_value=0).add(a4,fill_value=0).add(d1,fill_value=0).add(d2,fill_value=0)
    

    aratheon 11.0
    Blackwood 1.0
    Bolton 4.0
    Bracken 1.0
    Brave Companions 1.0
    Darry 2.0
    Free folk 1.0
    Frey 4.0
    Giants 1.0
    Glover 2.0
    Greyjoy 11.0
    Karstark 2.0
    Lannister 18.0
    Mallister 1.0
    Mormont 2.0
    Night's Watch 1.0
    Stark 16.0
    Thenns 1.0
    Tully 7.0
    Tyrell 2.0
    dtype: float64
    以上是所有参与战争的家族或势力,可以看到参与次数最多的家族Baratheon,Greyjoy,Lannister,Stark正是五王出生的家族,(Joffrey/Tommen 虽然姓Baratheon,但实际上是纯种的Lannister)。

    由于家族太多,这里选择两个来举例分析他们是谁的同盟 Tully 以及 Tyrell

    Tully 家族:

    # Tully 为attacker时的attacker_king是谁?
    attacker_king_tully = got_df[(got_df['attacker_1']=='Tully')|(got_df['attacker_2']=='Tully')|(got_df['attacker_3']=='Tully')|
           (got_df['attacker_4']=='Tully')].groupby('attacker_king').size()
    
    # Tully 为defender时的defender_king是谁?
    defender_king_tully = got_df[(got_df['defender_1']=='Tully')|(got_df['defender_2']=='Tully')].groupby('defender_king').size()
    
    # Tully 家族在战争中支持的国王
    attacker_king_tully.add(defender_king_tully,fill_value=0)
    

    attacker_king
    Robb Stark 7
    dtype: int64
    由此可见,Tully家族在7次战争中都支持了Robb Stark,这是理所应当的,因为Robb的母亲是Catelyn Tully...

    Tyrell家族:

    # Tyrell 为attacker时的attacker_king是谁?
    attacker_king_tyrell = got_df[(got_df['attacker_1']=='Tyrell')|(got_df['attacker_2']=='Tyrell')|(got_df['attacker_3']=='Tyrell')|
           (got_df['attacker_4']=='Tyrell')].groupby('attacker_king').size()
    
    # Tyrell 为defender时的defender_king是谁?
    defender_king_tyrell = got_df[(got_df['defender_1']=='Tyrell')|(got_df['defender_2']=='Tyrell')].groupby('defender_king').size()
    
    # Tyrell家族在战争中支持的国王
    attacker_king_tyrell.add(defender_king_tyrell,fill_value=0)
    

    defender_king
    Joffrey/Tommen Baratheon 2.0
    dtype: float64

    显然,Tyrell家族在2次战争中都支持了Joffrey。

    其实一开始,Tyrell家族是拥护Renly的,在Renly死后,Tyrell家族与Lannister家族结盟,小玫瑰Margaery Tyrell被许配给了Joffrey成为七国王后,在Joffrey死后又再度许配给了Tommen...

    6.所有战争前后经历了几年,每年的夏天的比例是多少?

    totalday = got_df.groupby('year').size()
    totalday
    

    year
    298 7
    299 19
    300 10
    dtype: int64

    战争前后经历了3年。

    # 每年的夏天的占比
    summer = got_df[got_df.summer == 1].groupby('year').size()
    summer.div(totalday,fill_value=0)
    

    year
    298 1.000000
    299 0.947368
    300 0.000000
    dtype: float64
    可以看出,298年和299年都是夏天,而300年没有夏天,凛冬将至。

    冰与火的小说中提到了,维斯特洛大陆的季节并没有规律,之前已经经历了十年长夏,而天气逐渐寒冷,所以这才印证了Stark家族的族语

    “Winter is coming”

    得出结论

    问题:上面的分析能够回答你提出的问题?通过这些分析你能够得出哪些结论?

    答案

    1.六位国王参战,比例如之前饼图所示
    2.每位国王的胜率如之前的柱状图所示,Balond胜率最高
    3.Joffrey更具侵略性,攻击别人次数最多
    4.pitched battle战争类型最多,ambush类型胜率最高
    5.具体家族及联盟关系详见分析
    6.战争前后经历了3年,300年已经没有夏天,凛冬将至

    反思

    问题:在你的分析和总结过程中是否存在逻辑严谨。是否有改进的空间? 你可以从下面的一些角度进行思考:

    1. 数据集是否完整,包含所有想要分析的数据?
    2. 在对数据进行处理的时候,你的操作(例如删除/填充缺失值)是否可能影响结论?
    3. 是否还有其他变量(本数据中没有)能够对你的分析有帮助?
    4. 在得出结论时,你是否混淆了相关性和因果性?

    答案

    数据包含了38场战斗,有些数据缺失,从统计学意义上,这个样本数量其实很小,并不能得出一般性结论。NaN的值采取了直接剔除的方式,也许并非最科学的方法,可能会对结果产生一定影响。数据来源源自奇幻小说,数据集内容本身就是虚构的,有些并不一定符合客观的因果关系。如前所述,有些数据存在明显的错误,也会影响统计结果。另外,战争行为本就是复杂的,任何偶然的因素都会影响结果,更何况这些战争是发生在文学作品里,并非真实的,比如Stannis击败Renly一役,最初Stannis在人数兵力上不占优,打不下风息堡,后来Stannis依靠黑魔法隔空就把Renly杀死了……像这种作者让谁死谁就得死的本身就没有什么逻辑因果关系,再深入用统计学来研究本身意义也不大。

    相关文章

      网友评论

          本文标题:五王之战分析 - 冰与火之歌-Udacity

          本文链接:https://www.haomeiwen.com/subject/twbotqtx.html