美国总统竞选赞助数据分析
本文来自阿里云天池实验室,案例原地址
自学数据分析的小王同学借鉴一下,自己写一遍,分析一遍,自己做的代码和结果如下
1.导入相关的python数据分析的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
2.数据载入和总览
2.1由于单个数据太大,我们把数据源分成三个0-50w行,50-100W行,100w+行
#数据读取
data_01=pd.read_csv(r'H:\阿里云\2012美国总统竞选赞助数据分析\data_01.csv')
data_02=pd.read_csv(r'H:\阿里云\2012美国总统竞选赞助数据分析\data_02.csv')
data_03=pd.read_csv(r'H:\阿里云\2012美国总统竞选赞助数据分析\data_03.csv')
2.2数据展示:
data_01读取前五行完毕
data_02读取前五行完毕
data_03读取前五行完毕
2.3合并数据(data_01,data_02,data_03)
data=pd.concat([data_01,data_02,data_03])
data.head()
2.4查看数据的信息,包括每个字段的名称、非空数量、字段的数据类型
data.info()
我们可以看出,contbr_employer和contbr_occupation 这两列字段的数量少一点,说明这里面有空值
2.5查看数据的概要
data.describe()
2.6缺失值的处理
从data.info()中,我们可以看到contbr_employer,contbr_occupation均有少量的缺失值,我们用not provided填充
data['contbr_employer'].fillna('not provided',inplace=True)
data['contbr_occupation'].fillna('not provided',inplace=True)
2.7 缺失值的查看
data[data['contbr_employer'].isnull()]
data[data['contbr_occupation'].isnull()]
data.info()
可以看到,缺失值已经没有了
2.8查看数据中总统候选人都有谁
print('共有{}位候选人,分别是'.format(len(data['cand_nm'].unique())))
data['cand_nm'].unique()
2.9通过搜索引擎等途径,获取到每个总统候选人的所属党派,建立字典parties,候选人名字作为键,所属党派作为对应的值
parties = {'Bachmann, Michelle': 'Republican',
'Cain, Herman': 'Republican',
'Gingrich, Newt': 'Republican',
'Huntsman, Jon': 'Republican',
'Johnson, Gary Earl': 'Republican',
'McCotter, Thaddeus G': 'Republican',
'Obama, Barack': 'Democrat',
'Paul, Ron': 'Republican',
'Pawlenty, Timothy': 'Republican',
'Perry, Rick': 'Republican',
"Roemer, Charles E. 'Buddy' III": 'Republican',
'Romney, Mitt': 'Republican',
'Santorum, Rick': 'Republican'}
2.10通过map映射函数,增加一列party存储党派信息
data['party']=data['cand_nm'].map(parties)#其中map的映射情况
#查看两个党派的情况
data['party'].value_counts()
#可以看出Republican(共和党)接受的赞助总金额更高,Democrat(民主党)获得的赞助次数更多一些
2.11查看一下数据表
其中各个字段名称含义
cand_nm – 接受捐赠的候选人姓名
contbr_nm – 捐赠人姓名
contbr_st – 捐赠人所在州
contbr_employer – 捐赠人所在公司
contbr_occupation – 捐赠人职业
contb_receipt_amt – 捐赠数额(美元)
contb_receipt_dt – 收到捐款的日期
2.12排序:按照职业汇总对赞助总金额进行排序,按照职位进行汇总,计算赞助总金额,展示前20项,发现不少职业是相同的,只不过是表达不一样而已,如C.E.O.与CEO,都是一个职业
data.groupby('contbr_occupation')['contb_receipt_amt'].sum().sort_values(ascending=False)[:20]
2.13利用函数进行数据转换:职业与雇主信息分析
许多职业都涉及相同的基本工作类型,下面我们来清理一下这样的数据(这里巧妙地利用了dict.get它允许没有映射关系的职业也能“通过”)
#建立一个职业对应字典,把相同职业的不同表达映射为对应的职业,比如把C.E.O.映射为CEO
occupation_map = {
'INFORMATION REQUESTED PER BEST EFFORTS':'NOT PROVIDED',
'INFORMATION REQUESTED':'NOT PROVIDED',
'SELF' : 'SELF-EMPLOYED',
'SELF EMPLOYED' : 'SELF-EMPLOYED',
'C.E.O.':'CEO',
'LAWYER':'ATTORNEY',
}
# 如果不在字典中,返回x
f = lambda x: occupation_map.get(x, x)
data.contbr_occupation = data.contbr_occupation.map(f)
#data.contbr_occupation相当于上面语句中的x
#data.contbr_occupation返回的结果与occupation_map中的键进行映射,如果相同返回对应的值,如果不同返回默认值
#contbr_occupation – 捐赠人职业
data.contbr_occupation.head()
同样地,对雇主信息进行类似转换
emp_mapping = {
'INFORMATION REQUESTED PER BEST EFFORTS' : 'NOT PROVIDED',
'INFORMATION REQUESTED' : 'NOT PROVIDED',
'SELF' : 'SELF-EMPLOYED',
'SELF EMPLOYED' : 'SELF-EMPLOYED',
}
# If no mapping provided, return x
f = lambda x: emp_mapping.get(x, x)
data.contbr_employer = data.contbr_employer.map(f)
这里我们演示一下dict.get()用法
dict_data ={1:'one',2:'two',3:'three',4:'four'}
print(dict_data.get(1))
print(dict_data.get(3))
print(dict_data.get(5))
print(dict_data.get(5,'notfound'))
输出结果
# 字典的get方法
# 如:list.get(k,d) 其中 get相当于一条if...else...语句,参数k在字典中,字典将返回list[k];如果参数k不在字典中则返回参数d,如果K在字典中则返回k对应的value值
# l = {5:2,3:4}
# print l.get(3,0)返回的值是4;
# Print l.get(1,0)返回值是0
3.1数据筛选
赞助包括退款(负的出资额),为了简化分析过程,我们限定数据集只有正出资额
data = data[data['contb_receipt_amt']>0]
3.2查看各候选人获得的赞助总金额,contb_receipt_amt – 捐赠数额(美元),cand_nm – 接受捐赠的候选人姓名
data.groupby('cand_nm')['contb_receipt_amt'].sum().sort_values(ascending=False)
从上面可以看出,赞助基本集中在Obama、Romney之间,为了更好的聚焦在两者间的竞争,我们选取这两位候选人的数据子集作进一步分析
3.3选取候选人为Obama、Romney的子集数据
data_vs = data[data['cand_nm'].isin(['Obama, Barack','Romney, Mitt'])].copy()
#data['cand_nm'].isin(['Obama, Barack','Romney, Mitt'])返回的是一个bool类型的值
# data[bool]返回的是具体的数据,所有为true的数据
#data.copy()把返回的数据进行复制
data_vs.head()
3.4离散化数据,用cut进行数据离散化
bins = np.array([0,1,10,100,1000,10000,100000,1000000,10000000])
labels = pd.cut(data_vs['contb_receipt_amt'],bins)
labels.head()
3.6按照党派、职业对赞助金额进行汇总,类似excel中的透视表操作,聚合函数为sum
by_occupation = data.pivot_table('contb_receipt_amt',index='contbr_occupation',columns='party',aggfunc='sum')
#过滤掉赞助金额小于200W的数据
over_2mm = by_occupation[by_occupation.sum(1)>2000000]
over_2mm
3.7绘图
over_2mm.plot(kind='bar')
3.8根据职业与雇主信息分组运算
我们接下来了解一下对Obama和Romney总出资最高的职业和雇主。注意,这里巧妙地利用了dict.get,它允许没有映射关系的职业也能“通过”
def get_top_amounts(group,key,n=5):
#传入groupby分组后的对象,返回按照key字段汇总的排序前n的数据
totals = group.groupby(key)['contb_receipt_amt'].sum()
return totals.sort_values(ascending=False)[:n]
grouped = data_vs.groupby('cand_nm')
grouped.apply(get_top_amounts,'contbr_occupation',n=7)
3.9同样的,使用get_top_amounts()对雇主进行分析处理
grouped.apply(get_top_amounts,'contbr_employer',n=10)
3.10labels是之前赞助金额离散化后的Series
grouped_bins = data_vs.groupby(['cand_nm',labels])
grouped_bins.size().unstack(0)
3.11接下来,我们再统计各区间的赞助金额
bucket_sums=grouped_bins['contb_receipt_amt'].sum().unstack(0)
bucket_sums
插播一个小实验
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
data11=DataFrame(np.arange(6).reshape((2,3)),index=pd.Index(['street1','street2']),columns=pd.Index(['one','two','three']))
print(data11)
print('-----------------------------------------\n')
data2=data11.stack()
data3=data2.unstack()
print(data2)
print('-----------------------------------------\n')
print(data3)
结果:
使用stack函数,将data的行索引[‘one’,‘two’,'three’]转变成列索引(第二层),便得到了 一个层次化的Series(data2),使用unstack函数,将data2的第二层列索引转变成行索引(默认的,可以改变),便又得到了DataFrame(data3)
这个实验主要演示stack函数和unstack函数
3.12Obama、Romney各区间赞助总金额
bucket_sums.plot(kind='bar')
3.13算出每个区间两位候选人收到赞助总金额的占比
normed_sums = bucket_sums.div(bucket_sums.sum(axis=1),axis=0)
normed_sums
3.14使用柱状图,指定stacked=True进行堆叠,即可完成百分比堆积图
可以看出,小额赞助方面,Obama获得的数量和金额比Romney多得多
3.15按照赞助人姓名分组计数,计算重复赞助次数最多的前20人
data.groupby('contbr_nm')['contbr_nm'].count().sort_values(ascending=False)[:20]
4.1str转datatime
我们可以使用to_datetime方法解析多种不同的日期表示形式。对标准日期格式(如ISO8601)的解析非常快。我们也可以指定特定的日期解析格式,如pd.to_datetime(series,format=’%Y%m%d’)
data_vs['time'] = pd.to_datetime(data_vs['contb_receipt_dt'])
data_vs['time'].head()
4.2以时间作为索引
data_vs.set_index('time',inplace=True)
data_vs.head()
4.3重采样和频度转换
重采样(Resampling)指的是把时间序列的频度变为另一个频度的过程。把高频度的数据变为低频度叫做降采样(downsampling),resample会对数据进行分组,然后再调用聚合函数。这里我们把频率从每日转换为每月,属于高频转低频的降采样。
vs_time = data_vs.groupby('cand_nm').resample('M')['cand_nm'].count()
vs_time.unstack(0)
4.4我们用面积图把11年4月-12年4月两位总统候选人接受的赞助笔数做个对比可以看出,越临近竞选,大家赞助的热情越高涨,奥巴马在各个时段都占据绝对的优势
fig1, ax1=plt.subplots(figsize=(32,8))
vs_time.unstack(0).plot(kind='area',ax=ax1,alpha=0.6)
plt.show()
本文代码放在我的github账号里:github账号链接
https://github.com/michael-wy/data-analysis