文章目录
DataWhale-Pandas数据分析-Task7
记录DataWhale的Pandas数据分析的学习过程,本次是期中测试,测试前面6章学的怎么样(划水的菜鸡瑟瑟发抖)。本篇文章中的测试题及源数据可以从此链接中下载,需要的可以点击链接自取。
【任务一】企业收入的多样性
思路:有两个表company和company_data,最后的结果应该是两个表连接成一个表,需要在company_data这个表中统计出熵,基本方法是先根据证券代码和日期分组求和,然后使用变换transform()方法将
p
(
x
i
)
∗
l
o
g
(
p
(
x
i
)
)
p(x_i)*log(p(x_i))
p(xi)∗log(p(xi))入到company_data表中,然后再根据先根据证券代码和日期分组求和,即可求出熵。
import pandas as pd
import numpy as np
df1 = pd.read_csv('company.csv')
df2 = pd.read_csv('company_data.csv')
df2=df2.loc[df2['收入额']>0,:]#df2中有负值,无法计算熵,所以先把负值所在的列删掉。
gb=df2.groupby(['证券代码','日期'])['收入额']#根据证券代码和日期分组
s1=df2['收入额']/gb.transform('sum')#使用变换transform()方法,求每一行收入与当年总收入的比例。
df2['temp']=-s1*np.log(s1)
df3=df2.groupby(['证券代码','日期'])['temp'].agg([('熵','sum')]).reset_index()#使用聚合函数求熵,生成新的表df3
df3['日期']=df3['日期'].apply(lambda x:int(x.split('/')[0]))#将表df3的日期一列改为和df1类型一样的方式,方便后面与df1连接
df1['证券代码']=df1['证券代码'].apply(lambda x:int(x[1:]))#将表df1的证券代码一列改为和df3类型一样,方便与df3连接。
df1=df1.merge(df3,on=['证券代码','日期'])#df1与df3连接,将熵加入到df1中.
df1.head()
>>>
> 证券代码 日期 熵
0 7 2014 3.070462
1 403 2015 2.790585
2 408 2016 2.818541
3 426 2015 3.084266
4 426 2016 2.988900
#看一下熵的分布特征
df1['熵'].describe()
>>>
>count 955.000000
mean 3.338334
std 0.410689
min 1.837489
25% 3.010368
50% 3.334039
75% 3.724752
max 4.068474
Name: 熵, dtype: float64
【任务二】
思路:我们先看一下原来表长什么样子:
很明显,原表是一个宽表,目标表格是一个长表,可以考虑先用使用melt()函数将宽表变为长表,先将队员昵称从列压缩到行,得到了包含昵称到编号映射关系的新的列:“昵称-编号”,然后利用这个映射关系,为每一个昵称找到其对应的编号,具体代码如下:
df=pd.read_excel('组队信息汇总表(Pandas).xlsx')
#导入excel表格以后,列索引的值有些混乱,为了后续方便找到昵称和编号的对应关系,先重新设置一下索引的值。
df=df.rename(columns={'队员_群昵称':'队员_群昵称.1','队员_群昵称.1':'队员_群昵称.2','队员_群昵称.2':'队员_群昵称.3','队员_群昵称.3':'队员_群昵称.4',\
'队员_群昵称.4':'队员_群昵称.5','队员_群昵称.5':'队员_群昵称.6','队员_群昵称.6':'队员_群昵称.7','队员_群昵称.7':'队员_群昵称.8',\
'队员_群昵称.8':'队员_群昵称.9','队员_群昵称.9':'队员_群昵称.10','队员10编号':'队员10 编号'})
#使用melt将队员昵称从列压缩到行
df1=df.melt(value_vars=['队长_群昵称','队员_群昵称.1','队员_群昵称.2','队员_群昵称.3','队员_群昵称.4','队员_群昵称.5',\
'队员_群昵称.6','队员_群昵称.7','队员_群昵称.8','队员_群昵称.9','队员_群昵称.10'],#压缩的列。
var_name='昵称-编号',#将压缩后形成的新列命名为昵称-编号
value_name='昵称',
id_vars=['所在群','队伍名称','队长编号','队员1 编号','队员2 编号','队员3 编号','队员4 编号','队员5 编号',\
'队员6 编号','队员7 编号','队员8 编号','队员9 编号','队员10 编号'])
df1=df1.loc[df1['昵称'].notnull(),:]#因为有的队队员人数不足10个,所以这里需要去除昵称为空的行。
#根据‘昵称-编号’这一列找到‘昵称’对应的编号。
def func(x):
if x['昵称-编号']=='队长_群昵称':
return int(x['队长编号'])
else:
return int(x['队员'+x['昵称-编号'].split('.')[1]+' 编号'])
df1['编号']=df1.apply(func,axis=1)
df1['是否队长']=df1['昵称-编号'].apply(lambda x: 1 if x=='队长_群昵称' else 0)
df_final=df1[['是否队长','队伍名称','昵称','编号']].sort_values(['队伍名称','是否队长'],ascending=[True,False]).reset_index(drop=True)
结果:
【任务三】
1.思路:先分组后统计每个县投票总人数,再与人口表连接,求出投票总人数超过总数一半的县.
df1 = pd.read_csv('county_population.csv')
df2 = pd.read_csv('president_county_candidate.csv')
df_temp=df2.groupby(['state','county'])['total_votes'].agg({'sum'})#先分组,再求和
df_temp.index=df_temp.index.map(lambda x:'.'+x[1]+', '+x[0])#将两层列索引压缩成一层,方便后续与df1连接
df_temp=df_temp.reset_index().rename(columns={'index':'US County'})#将列名重命名为和df1一样。
df_m=df1.merge(df_temp,on='US County')#df_temp与df1连接
s_country=df_m.loc[df_m['sum']/df_m['Population']>0.5]['US County'].reset_index(drop=True)#根据条件索引
>>>
>0 .Choctaw County, Alabama
1 .Clarke County, Alabama
2 .Clay County, Alabama
3 .Colbert County, Alabama
4 .Conecuh County, Alabama
Name: US County, dtype: object
2 .思路:先根据洲名和候选人名分组统计每个候选人在一个州的总票数,然后使用pivot()函数对列表进行变形,最后生成一个每个候选在全国的总选票的Series加入到列表中,根据总选票的多少,使用sort_values(axis=1)对列进行排序。
df_temp=df2.groupby(['state','candidate'])['total_votes'].sum().reset_index()#分组
df_temp=df_temp.pivot(index='state',columns='candidate',values='total_votes')#使用pivot()变形
s=pd.Series(df_temp.apply(lambda x:x.sum()),name='all')#生成一个新的Series,计算每个候选在全国的总选票。
df_temp=df_temp.append(s)#将s加入到表格df_temp中
df_temp.sort_values(by='all',ascending=False,axis=1)#使用sort_values(axis=1)对列进行排序
结果的表格太宽,截图显示一下:
3.