天池大数据竞赛 Spaceack带你利用Pandas,趋势图与桑基图分析美国选民候选人喜好度

长文预警

竞赛地址: https://tianchi.aliyun.com/competition/entrance/531837/introduction

首先,这是一篇面向新人的教程导向的分析文章,(by the way其实我也是新手,从比赛开始才学的Pandas库,这也是我的一篇学习笔记),所以会包含很多函数的基础用法,解题思路等等, 流程会比较详细。

其次,本文在官方教程基础上会加入创新内容,但是绝不会为了用而用某种新方法,一定本着分析数据有所帮助的原则和对数据敬畏的态度来做。

再者,为了更方便学习,请点击右上角蓝色的 Star 和 Fork 按钮。

数据集下载:
https://tianchi.aliyun.com/competition/entrance/531837/introduction?spm=5176.12281973.1005.3.11ae1f540dSho6

# 导入相关处理包
import pandas as pd
# 加入下面这条语句可以在 JupyterLab 上渲染画布( JupyterLab 是天池实验室的一部分)
%matplotlib inline

数据预处理

数据预处理部分包含 数据导入数据探索数据整合格式转换等多个步骤。这些步骤可穿插执行。

这里第一步就是数据导入

Pandas 提供的 IO 工具组支持多种数据格式类型,包括基础的 CSV,JSON,SQL 格式。

这里用到 read_csv 方法

此方法第一个参数为文件路径, 这里对应着天池实验室挂载的数据,因为在 download 同一目录下, 所以直接写文件名即可。

第二个参数 sep 为分隔符,用于将每行分解为若干列。默认是,逗号。

第三个参数 names 为列名列表,当文件不包含列名时使用,列名列表中不允许有重复值。

扩展:若我们要分析文件中包含列名呢?有个 header 参数可以使用,当列名是首行时,设置 header=0。举一反三,有时候文件首行是文件的标题,第二行才是列名,那么设置 header=1 即可。

将委员会和候选人一一对应,通过CAND_ID关联两个表

由于候选人和委员会的联系表中无候选人姓名,只有候选人ID(CAND_ID),所以需要通过CAND_ID 从候选人表中获取到候选人姓名,最终得到候选人与委员会联系表 ccl

# 读取候选人信息,由于原始数据没有表头,需要添加表头
candidates = pd.read_csv("weball20.txt", sep = '|',names=['CAND_ID','CAND_NAME','CAND_ICI','PTY_CD','CAND_PTY_AFFILIATION','TTL_RECEIPTS',
                                                          'TRANS_FROM_AUTH','TTL_DISB','TRANS_TO_AUTH','COH_BOP','COH_COP','CAND_CONTRIB',
                                                          'CAND_LOANS','OTHER_LOANS','CAND_LOAN_REPAY','OTHER_LOAN_REPAY','DEBTS_OWED_BY',
                                                          'TTL_INDIV_CONTRIB','CAND_OFFICE_ST','CAND_OFFICE_DISTRICT','SPEC_ELECTION','PRIM_ELECTION','RUN_ELECTION'
                                                          ,'GEN_ELECTION','GEN_ELECTION_PRECENT','OTHER_POL_CMTE_CONTRIB','POL_PTY_CONTRIB',
                                                          'CVG_END_DT','INDIV_REFUNDS','CMTE_REFUNDS'])
# 读取候选人和委员会的联系信息
ccl = pd.read_csv("ccl.txt", sep = '|',names=['CAND_ID','CAND_ELECTION_YR','FEC_ELECTION_YR','CMTE_ID','CMTE_TP','CMTE_DSGN','LINKAGE_ID'])

数据整合

我们现在已导入 candidates 候选人信息表,ccl 候选人与委员会关联表两张表。均为 DataFrame 类型。

聪明的你会发现,两个表的表头都包含 CAND_ID 这个字段,那么这两张表会根据这个字段有所联系。那么我们可以用 merge 这个神奇的方法合并两张表。

merge 方法有几个重要的参数如下:

  1. left : 在这里就是我们要合并左边的 ccl 表。
  2. right : 在这里就是我们要合并右边的 candidates 表。
  3. how : 这是个带有默认参数的隐藏参数,默认为 inner (内连接),学过 SQL 的同学都懂得~ 肯定还会包含 outer(外链接)、left(左连接)、right(右连接)
  4. on :这个参数用来连接列名,若没有其它连接项,默认会把左右两个表头的交集字段作为连接字段。下面的代码是省略的写法,也可以这样表示 ccl = pd.merge(ccl, candidates, on="CAND_ID", how="inner")
  5. left_on :用来指定左侧作为连接的表头。
  6. right_on:用来指定右侧作为连接的表头, 下面的代码是省略的写法,也可以这样表示 ccl = pd.merge(ccl, candidates, left_on="CAND_ID", right_on="CAND_ID", how="inner")
# 关联两个表数据
ccl = pd.merge(ccl, candidates)
# 提取出所需要的列
ccl = pd.DataFrame(ccl, columns=[ 'CMTE_ID','CAND_ID', 'CAND_NAME','CAND_PTY_AFFILIATION'])
# 读取个人捐赠数据,由于原始数据没有表头,需要添加表头
# 提示:读取本文件大概需要5-10s
itcont = pd.read_csv('itcont_2020_20200722_20200820.txt', sep='|',names=['CMTE_ID','AMNDT_IND','RPT_TP','TRANSACTION_PGI','IMAGE_NUM','TRANSACTION_TP','ENTITY_TP','NAME','CITY','STATE','ZIP_CODE','EMPLOYER','OCCUPATION','TRANSACTION_DT','TRANSACTION_AMT','OTHER_ID','TRAN_ID','FILE_NUM','MEMO_CD','MEMO_TEXT','SUB_ID'],low_memory=False)
# 将候选人与委员会关系表ccl和个人捐赠数据表itcont合并,通过 CMTE_ID
c_itcont =  pd.merge(ccl, itcont)

数据探索

# 查看目前数据前6行, 若省略行数,默认显示5行
c_itcont.head(6)
CMTE_IDCAND_IDCAND_NAMECAND_PTY_AFFILIATIONAMNDT_INDRPT_TPTRANSACTION_PGIIMAGE_NUMTRANSACTION_TPENTITY_TP...EMPLOYEROCCUPATIONTRANSACTION_DTTRANSACTION_AMTOTHER_IDTRAN_IDFILE_NUMMEMO_CDMEMO_TEXTSUB_ID
0C00698084H0AZ02182MORGAN, JOSEPH DAVIDREPAQ3P202020201006928503136915IND...RETIREDRETIRED7242020100NaNSA11AI.49091444070NaNNaN4100820201856947991
1C00698084H0AZ02182MORGAN, JOSEPH DAVIDREPAQ3P202020201006928503136915IND...VA HOSPITALLAB TECH724202040NaNSA11AI.49081444070NaNNaN4100820201856947993
2C00698084H0AZ02182MORGAN, JOSEPH DAVIDREPAQ3P202020201006928503137015IND...VA HOSPITALLAB TECH731202040NaNSA11AI.49161444070NaNNaN4100820201856947994
3C00725697H0AZ03461WOOD, DANIELREPAQ3G202020201007928505251615IND...POWERS-LEAVITTINSURANCE AGENT8102020300NaNSA11AI.46831444556NaNNaN4100920201857257629
4C00725697H0AZ03461WOOD, DANIELREPAQ3G202020201007928505251815IND...UNEMPLOYEDNaN8072020500NaNSA11AI.46121444556NaNNaN4100920201857257635
5C00725697H0AZ03461WOOD, DANIELREPAQ3G202020201007928505251915IND...SELF-EMPLOYEDDVM7312020500NaNSA11AI.45931444556NaNNaN4100920201857257636

6 rows × 24 columns

# 查看目前数据后3行, 若省略行数,默认显示5行
c_itcont.head(n=3)
CMTE_IDCAND_IDCAND_NAMECAND_PTY_AFFILIATIONAMNDT_INDRPT_TPTRANSACTION_PGIIMAGE_NUMTRANSACTION_TPENTITY_TP...EMPLOYEROCCUPATIONTRANSACTION_DTTRANSACTION_AMTOTHER_IDTRAN_IDFILE_NUMMEMO_CDMEMO_TEXTSUB_ID
0C00698084H0AZ02182MORGAN, JOSEPH DAVIDREPAQ3P202020201006928503136915IND...RETIREDRETIRED7242020100NaNSA11AI.49091444070NaNNaN4100820201856947991
1C00698084H0AZ02182MORGAN, JOSEPH DAVIDREPAQ3P202020201006928503136915IND...VA HOSPITALLAB TECH724202040NaNSA11AI.49081444070NaNNaN4100820201856947993
2C00698084H0AZ02182MORGAN, JOSEPH DAVIDREPAQ3P202020201006928503137015IND...VA HOSPITALLAB TECH731202040NaNSA11AI.49161444070NaNNaN4100820201856947994

3 rows × 24 columns

# 查看数据规模 多少行 多少列
c_itcont.shape
(756205, 24)
# 查看整体数据信息,包括每个字段的名称、非空数量、字段的数据类型
c_itcont.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 756205 entries, 0 to 756204
Data columns (total 24 columns):
CMTE_ID                 756205 non-null object
CAND_ID                 756205 non-null object
CAND_NAME               756205 non-null object
CAND_PTY_AFFILIATION    756205 non-null object
AMNDT_IND               756205 non-null object
RPT_TP                  756205 non-null object
TRANSACTION_PGI         756205 non-null object
IMAGE_NUM               756205 non-null int64
TRANSACTION_TP          756205 non-null object
ENTITY_TP               756205 non-null object
NAME                    756205 non-null object
CITY                    756159 non-null object
STATE                   756160 non-null object
ZIP_CODE                756092 non-null object
EMPLOYER                737413 non-null object
OCCUPATION              741294 non-null object
TRANSACTION_DT          756205 non-null int64
TRANSACTION_AMT         756205 non-null int64
OTHER_ID                647200 non-null object
TRAN_ID                 756205 non-null object
FILE_NUM                756205 non-null int64
MEMO_CD                 220 non-null object
MEMO_TEXT               655693 non-null object
SUB_ID                  756205 non-null int64
dtypes: int64(5), object(19)
memory usage: 144.2+ MB
# 查看数据表中数据类型的列的数据分布情况
c_itcont.describe()
IMAGE_NUMTRANSACTION_DTTRANSACTION_AMTFILE_NUMSUB_ID
count7.562050e+057.562050e+057.562050e+057.562050e+057.562050e+05
mean2.020090e+177.887799e+061.504307e+021.439133e+064.091288e+18
std4.071886e+113.857874e+052.320452e+032.325325e+034.642365e+15
min2.020072e+177.222020e+06-5.600000e+031.427865e+064.072420e+18
25%2.020092e+177.312020e+062.000000e+011.440015e+064.092520e+18
50%2.020092e+178.102020e+063.500000e+011.440320e+064.093020e+18
75%2.020092e+178.152020e+061.000000e+021.440320e+064.093020e+18
max2.020101e+178.202020e+061.500000e+061.445380e+064.101020e+18

格式转换

#空值处理,统一填充 NOT PROVIDED
c_itcont['STATE'].fillna('NOT PROVIDED',inplace=True)
c_itcont['EMPLOYER'].fillna('NOT PROVIDED',inplace=True)
c_itcont['OCCUPATION'].fillna('NOT PROVIDED',inplace=True)
# 对日期TRANSACTION_DT列进行处理
c_itcont['TRANSACTION_DT'] = c_itcont['TRANSACTION_DT'] .astype(str)
# 将日期格式改为年月日  7242020	
c_itcont['TRANSACTION_DT'] = [i[3:7]+i[0]+i[1:3] for i in c_itcont['TRANSACTION_DT'] ]

绘制收到捐赠额最多的两位候选人的总捐赠额变化趋势图

# 计算每个总统候选人所获得的捐款总额,然后排序,取前二位
c_itcont.groupby("CAND_NAME").sum().sort_values("TRANSACTION_AMT",ascending=False).head(2)
IMAGE_NUMTRANSACTION_AMTFILE_NUMSUB_ID
CAND_NAME
BIDEN, JOSEPH R JR1.025834e+2368111142.07.307496e+112.077270e+24
TRUMP, DONALD J.1.181873e+2216594982.08.417584e+102.396038e+23
# 提取需要的数据列
c_itcont0 = pd.DataFrame(c_itcont, columns=[ 'CAND_NAME', 'TRANSACTION_AMT', 'TRANSACTION_DT'])

# 已知所获得的捐款总额前两位的总统候选人分别是'BIDEN, JOSEPH R JR', 'TRUMP, DONALD J.', 筛选出来
c_itcont1 = c_itcont0[c_itcont0['CAND_NAME'].isin(['BIDEN, JOSEPH R JR', 'TRUMP, DONALD J.'])]

# 因为同一天会有多笔捐款入帐,需要做分组求和
c_itcont2 = c_itcont1.groupby(['CAND_NAME', 'TRANSACTION_DT']).sum()

# 因为我们要看总额的趋势图,所以要做累加
c_itcont3 = c_itcont2.groupby(['CAND_NAME', ]).cumsum()

# 现在很快可以达到预期目标了
c_itcont3
TRANSACTION_AMT
CAND_NAMETRANSACTION_DT
BIDEN, JOSEPH R JR2020722888622
20207231852227
20207243024292
20207253943847
20207265052629
20207276150050
20207287625248
20207298900851
20207309964382
202073112305972
202080113391021
202080214208260
202080315063070
202080416138452
202080517317433
202080618293448
202080719246279
202080820152637
202080920996972
202081022015682
202081126905056
202081232932121
202081338604052
202081441666574
202081544125928
202081646254874
202081749826137
202081853584270
202081958989963
202082068111142
TRUMP, DONALD J.2020722330603
2020723554920
2020724828209
20207251035861
20207261529042
20207272044076
20207282499171
20207293216022
20207304346359
20207316338855
20208016688166
20208026925401
20208037273299
20208047862177
20208058175442
20208068501605
20208078899471
20208089124955
20208099404411
202081010286254
202081110856855
202081211540551
202081312298919
202081412717476
202081513483142
202081613812398
202081714453930
202081815086445
202081915665254
202082016594982
# 整理下排列索引,这里用到了索引和列标题转换与转置操作
c_itcont4 = c_itcont3.unstack().T
c_itcont4
CAND_NAMEBIDEN, JOSEPH R JRTRUMP, DONALD J.
TRANSACTION_DT
TRANSACTION_AMT2020722888622330603
20207231852227554920
20207243024292828209
202072539438471035861
202072650526291529042
202072761500502044076
202072876252482499171
202072989008513216022
202073099643824346359
2020731123059726338855
2020801133910216688166
2020802142082606925401
2020803150630707273299
2020804161384527862177
2020805173174338175442
2020806182934488501605
2020807192462798899471
2020808201526379124955
2020809209969729404411
20208102201568210286254
20208112690505610856855
20208123293212111540551
20208133860405212298919
20208144166657412717476
20208154412592813483142
20208164625487413812398
20208174982613714453930
20208185358427015086445
20208195898996315665254
20208206811114216594982

绘制收到捐赠额最多的两位候选人的总捐赠额变化趋势图

这里使用 plot 方法绘制趋势图,(由于天池实验室环境不是最新的库,兼容问题会报警告,但是不影响出图。 我在其它环境测试没问题,图的横坐标会有日期显示的。)

# grid参数 用来显示后面的辅助网格线, rot 使横坐标的日期以45度排列, 不会导致产生字符过长导致叠加的问题。(由于天池实验室环境不是最新的库,兼容问题会报警告,横坐标的日期标注无法显示。)
c_itcont4.plot(grid=True, rot=45)

在这里插入图片描述

结论

由趋势图可以看出,在7月22日至8月20日期间,拜登收到的捐款总额明显高于特朗普。且在8月份有更为显著的变化。

使用桑基图分析美国各州对党派的贡献度

桑基图(Sankey),即桑基能量分流图,是一种高级可视化图形。常用于金融等数据的可视化分析。最明显的特征就是,始末端的分支宽度总和相等,即所有主支宽度的总和应与所有分出去的分支宽度的总和相等,保持能量的平衡。

一个州的捐款额可能会流向不同的党派,用桑基图表示的效果就非常好。可以很清楚看出某个党派的贡献流向。

这里要用到第三方库 pyecharts,用来画桑吉图比较方便,还支持交互式操作(鼠标悬停某条能量线高亮并显示金额数量),首先安装第三方库

!pip install pyecharts --user
Looking in indexes: https://mirrors.aliyun.com/pypi/simple
Requirement already satisfied: pyecharts in /data/nas/workspace/envs/python3.6/site-packages (1.9.0)
Requirement already satisfied: prettytable in /data/nas/workspace/envs/python3.6/site-packages (from pyecharts) (1.0.1)
Requirement already satisfied: simplejson in /data/nas/workspace/envs/python3.6/site-packages (from pyecharts) (3.17.2)
Requirement already satisfied: jinja2 in /opt/conda/lib/python3.6/site-packages (from pyecharts) (2.11.2)
Requirement already satisfied: setuptools in /opt/conda/lib/python3.6/site-packages (from prettytable->pyecharts) (49.6.0)
Requirement already satisfied: wcwidth in /opt/conda/lib/python3.6/site-packages (from prettytable->pyecharts) (0.2.5)
Requirement already satisfied: MarkupSafe>=0.23 in /opt/conda/lib/python3.6/site-packages (from jinja2->pyecharts) (1.1.1)
# 提取需要的数据列
c_itcont5 = pd.DataFrame(c_itcont, columns=[ 'STATE', 'TRANSACTION_AMT', 'CAND_PTY_AFFILIATION'])
# 提取党派集合
c_itcont_CAND_PTY_AFFILIATION = pd.DataFrame(c_itcont5,columns=['CAND_PTY_AFFILIATION'])
cgc = c_itcont_CAND_PTY_AFFILIATION.groupby('CAND_PTY_AFFILIATION').count()
node2 = list(cgc.index)
node2
['BDY',
 'CON',
 'DEM',
 'DFL',
 'GRE',
 'IND',
 'LIB',
 'NON',
 'NPA',
 'OTH',
 'REP',
 'UNK']
# 提取州集合
c_itcont_STATE = pd.DataFrame(c_itcont5,columns=['STATE'])
sgc = c_itcont_STATE.groupby('STATE').count()
node1 = list(sgc.index)
# 为方便阅读, 引入汉化字典
scp = {'AA': '美洲军',
 'AE': '军事地区',
 'AK': '阿拉斯加州',
 'AL': '阿拉巴马州',
 'AP': '太平洋军事机构',
 'AR': '阿肯色州',
 'AS': '美属萨摩亚群岛',
 'AZ': '阿利桑那州',
 'CA': '加利福尼亚州',
 'CO': '科罗拉多州',
 'CT': '康涅狄格州',
 'DC': '华盛顿DC',
 'DE': '特拉华州',
 'FL': '佛罗里达州',
 'FM': 'FM联邦',
 'GA': '乔治亚州',
 'GU': '关岛',
 'HI': '夏威夷州',
 'IA': '爱荷华州',
 'ID': '爱达荷州',
 'IL': '伊利诺斯州',
 'IN': '印第安纳州',
 'KS': '堪萨斯州',
 'KY': 'KY',
 'LA': '路易斯安那州',
 'MA': '马萨诸塞州',
 'MD': '马里兰州',
 'ME': '缅因州',
 'MI': '密歇根州',
 'MN': '明尼苏达州',
 'MO': '密苏里州',
 'MP': 'MP',
 'MS': '密西西比州',
 'MT': '蒙大拿州',
 'NC': '北卡罗来纳州',
 'ND': '北达科他州',
 'NE': '内布拉斯加州',
 'NH': '新罕布什尔州',
 'NJ': '新泽西州',
 'NM': '新墨西哥州',
 'NOT PROVIDED': 'NOT PROVIDED',
 'NV': '内华达州',
 'NY': '纽约州',
 'OH': '俄亥俄州',
 'OK': 'OK',
 'OR': '俄勒冈州',
 'PA': '宾夕法尼亚州',
 'PR': 'PR',
 'PW': 'PW',
 'RI': '罗得岛州',
 'SC': '南卡罗来纳州',
 'SD': '南达科他州',
 'TN': '田纳西州',
 'TX': '得克萨斯州',
 'UT': '犹他州',
 'VA': '弗吉尼亚州',
 'VI': 'VI',
 'VT': '佛蒙特州',
 'WA': '华盛顿州',
 'WI': '威斯康辛州',
 'WV': '西弗吉尼亚州',
 'WY': '怀俄明州',
 'ZZ': 'ZZ'}

# 将集合加入到节点列表,nodes需要把桑基图中出现的名称全部设置进去,并且要保证links中的名称与name相同
nodes = []
for n in node1:
    nodes.append({'name': scp[n]})
for n in node2:
    nodes.append({'name': n})
# 做分组聚合
cgs = c_itcont5.groupby(['STATE','CAND_PTY_AFFILIATION']).sum()
# 将聚合结果加入到链接列表, links代表节点关系,source表示起点,target表示终点,需要将节点关系全部输入进去,value表示节点长度
links = []
for row in cgs.iterrows():
    links.append({'source': scp[row[0][0]], 'target': row[0][1], 'value': int(row[1][0])})
from pyecharts import options as opts
from pyecharts.charts import Page, Sankey
sankey = Sankey(init_opts=opts.InitOpts(width="1024", height="768"))		#可以设置大小和图标名称
sankey.add(
    '各州捐款额流向图',				#名称
    nodes,					#输入节点,如果导入json数据,nodes=json['nodes]
    links,					#输入关系,nodes=json['links']
    linestyle_opt=opts.LineStyleOpts(opacity=0.3, curve=0.5, color="source", width=10),
    label_opts=opts.LabelOpts(position="right", is_show=True, color='red'),
    node_gap=1
)
sankey.render()
# 生成的桑基图可通过下方目录查看

在这里插入图片描述

'/data/nas/workspace/jupyter/download/render.html'

结论

由各州全款额流向图可以非常快速的得知:加利福尼亚州,纽约州,马萨诸塞州在7月22日至8月20日是对民主党贡献最多的三大州。

佛罗里达州和德克萨斯州对两大党的贡献几乎相同,但更倾向于共和党,也是对共和党贡献较大的两个州。

桑基图会包含很多数据元素,通过桑基图可以探索更多的数据,例如去除两大党的情况和仅比较两大党的情况等等。


包揽了此次数据分析比赛所有奖项!好开心!
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Spaceack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值