其他分享
首页 > 其他分享> > pandas进阶 期中练习

pandas进阶 期中练习

作者:互联网

Pandas进阶 期中练习

pandas进阶系列根据datawhale远昊大佬的joyful pandas教程写一些自己的心得和补充

【任务一】企业收入的多样性

【题目描述】一个企业的产业收入多样性可以仿照信息熵的概念来定义收入熵指标:
I = − ∑ i p ( x i ) log ⁡ ( p ( x i ) ) \mathrm{I}=-\sum_{\mathrm{i}} \mathrm{p}\left(\mathrm{x}_{\mathrm{i}}\right) \log \left(\mathrm{p}\left(\mathrm{x}_{\mathrm{i}}\right)\right) I=−i∑​p(xi​)log(p(xi​))
其中 p(xi)
是企业该年某产业收入额占该年所有产业总收入的比重。在company.csv中存有需要计算的企业和年份,在company_data.csv中存有企业、各类收入额和收入年份的信息。现请利用后一张表中的数据,在前一张表中增加一列表示该公司该年份的收入熵指标
I。
【数据下载】链接:https://pan.baidu.com/s/1leZZctxMUSW55kZY5WwgIw 密码:u6fd
【我的思路】
按公司和日期分组,求出收入额与总额的比值,并利用比值求每个项的熵再求出每个组的增益,然后按公司和日期将两表合并

import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
df1 = pd.read_csv('../data/Company_1.csv')
df2 = pd.read_csv('../data/company_data.csv')

先看一下两个数据集的结构

df1.head()
证券代码日期
0#0000072014
1#0004032015
2#0004082016
3#0004082017
4#0004262015
df2.head()
证券代码日期收入类型收入额
012008/12/3111.084218e+10
112008/12/3121.259789e+10
212008/12/3131.451312e+10
312008/12/3141.063843e+09
412008/12/3158.513880e+08

结果是要求每个公司每年的收入熵,因此应该考虑在收入表中按企业和年份分组
查看一下分组后有没有出现收入类型重复的情况,因为如果重复的话应该把同类型的收入求和

tmp = df2[['证券代码', '日期', '收入类型']]
tmp.drop_duplicates().equals(tmp)
True

结果表明没有重复
然后按照公式一步一步求,p是每个公司每日期的比例,因此先求出每个小组的收入额的和,再求p,根据p和log p求出每一项的熵,然后求和就是每个组的信息增益,这里因为有0值,求log以后会变成无限大,无限大与0相乘后会变成空值,所以需要对空值处理一下使其为0

df2['total'] = df2.groupby(['证券代码', '日期'])['收入额'].transform('sum')
df2['ratio'] = df2['收入额'] / df2['total']
df2['entropy'] = df2['ratio']*np.log(df2['ratio'])
df2['entropy'].fillna(0, inplace=True)
df2['I'] = -df2.groupby(['证券代码', '日期'])['entropy'].transform('sum')
df2.tail()
证券代码日期收入类型收入额totalratioentropyI
9640179009572016/12/31120.006.399964e+080.0000000.0000002.178318
9640189009572016/12/31130.006.399964e+080.0000000.0000002.178318
9640199009572016/12/311452072238.976.399964e+080.081363-0.2041272.178318
9640209009572016/12/31150.006.399964e+080.0000000.0000002.178318
9640219009572016/12/311652072238.976.399964e+080.081363-0.2041272.178318
res = df2[['证券代码', '日期', 'I']].drop_duplicates()
res.head()
证券代码日期I
012008/12/312.085159
1412009/12/311.671752
2212010/12/312.108355
3412011/12/313.150479
7212012/12/312.718759

由于证券代码和日期的格式对不上,所以更改一下格式

res['证券代码'] = res['证券代码'].apply(lambda x: '#' + (6-len(str(x)))*'0' + str(x))
res['日期'] = res['日期'].apply(lambda x: int(str(x)[:4]))
res.head()
证券代码日期I
0#00000120082.085159
14#00000120091.671752
22#00000120102.108355
34#00000120113.150479
72#00000120122.718759

这里发现merge的时候需要保持两个表中的列的类型是一样的,原本在公司表中日期是int类型,而公司数据表中日期是object类型,因此在上一步做数据转换的时候要把类型也显式转换一下
最后再按照原表的顺序求信息增益

df1 = df1.merge(res, on=['证券代码', '日期'])
df1.head()
证券代码日期I
0#00000720143.070462
1#00040320152.790585
2#00040820162.818541
3#00042620153.084266
4#00042620162.988900

【使用场景】
本道题中提出的信息增益是决策树中常用的算法,用来求结点分裂时的最优分裂特征,最优分裂特征应当是信息增益(比)最高的,类似信息增益作用的算法还有基尼指数,基尼指数相对于信息增益比的优势是其计算更简便,不涉及log计算,而且是二叉树,优化了计算速度,在效率上由于信息增益比,在效果上是信息增益比的一种近似代替。
这里我根据这道题的数据再计算一下基尼指数,并分别计算一下两种算法的效率

基尼指数的公式:
Gini ⁡ ( D ) = ∑ i = 1 n p ( x i ) ∗ ( 1 − p ( x i ) ) = 1 − ∑ i = 1 n p ( x i ) 2 \begin{aligned} \operatorname{Gini}(D) &=\sum_{i=1}^{n} p\left(x_{i}\right) *\left(1-p\left(x_{i}\right)\right) &=1-\sum_{i=1}^{n} p\left(x_{i}\right)^{2} \end{aligned} Gini(D)​=i=1∑n​p(xi​)∗(1−p(xi​))​=1−i=1∑n​p(xi​)2​

df2['ratio_2'] = df2['ratio'] * df2['ratio']
df2 = df2.groupby(['证券代码', '日期'])['ratio_2'].sum().reset_index()
df2.head()
证券代码日期ratio_2
012008/12/310.148788
112009/12/310.230552
212010/12/310.139320
312011/12/310.057870
412012/12/310.086869
df2['gini'] = 1 - df2['ratio_2']
df2['证券代码'] = df2['证券代码'].apply(lambda x: '#' + (6-len(str(x)))*'0' + str(x))
df2['日期'] = df2['日期'].apply(lambda x: int(str(x)[:4]))
df2 = df2[['证券代码', '日期', 'gini']]
df2.head()
证券代码日期gini
0#00000120080.851212
1#00000120090.769448
2#00000120100.860680
3#00000120110.942130
4#00000120120.913131
res = res.merge(df2, on=['证券代码', '日期'])
res.head()
证券代码日期Igini
0#00000120082.0851590.851212
1#00000120091.6717520.769448
2#00000120102.1083550.860680
3#00000120113.1504790.942130
4#00000120122.7187590.913131
import seaborn as sns
sns.distplot(res['I'])

在这里插入图片描述

sns.distplot(res['gini'])

在这里插入图片描述

两个好像大致分布是一样的吧0.0
不过可以看出gini的结果更为平滑一些
再比较一下计算效率

df2 = pd.read_csv('../data/company_data.csv')
df2['total'] = df2.groupby(['证券代码', '日期'])['收入额'].transform('sum')
df2['ratio'] = df2['收入额'] / df2['total']
%%timeit
df2['entropy'] = df2['ratio']*np.log(df2['ratio'])
df2['I'] = -df2.groupby(['证券代码', '日期'])['entropy'].transform('sum')
151 ms ± 25.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
df2 = pd.read_csv('../data/company_data.csv')
df2['total'] = df2.groupby(['证券代码', '日期'])['收入额'].transform('sum')
df2['ratio'] = df2['收入额'] / df2['total']
df2.head()
%%timeit
df2['ratio_2'] = df2['ratio'] * df2['ratio']
df3 = df2.groupby(['证券代码', '日期'])['ratio_2'].sum().reset_index()
df3['gini'] = 1 - df3['ratio_2']
124 ms ± 21.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

两段代码里都包含了一个groupby的操作,因此计算不是很精确,不过还是可以看出基尼指数的计算速度相较于信息增益快了20%左右

【第二题】组队学习信息表的变换

【题目描述】请把组队学习的队伍信息表变换为如下形态,其中“是否队长”一列取1表示队长,否则为0
数据非公开,这里不提供

【我的思路】这是个宽表变长表的操作,应该是可以用wide_to_long进行操作的,但还没想好wide_to_long怎么操作。
目前我的思路是先提取出所有队长的列,然后把每个队员的列的数据按列插入到队长表中

ps.后记:提交完之后我看到了Gocara大佬的答案,明白了wide_to_long的做法,这里我在我的第一版内容之后又加了wide_to_long的做法,并比对一下两种做法的效率

teams = pd.read_excel('../data/team_info.xlsx', engine='openpyxl')
teams.head()
所在群队伍名称队长编号队长_群昵称队员1 编号队员_群昵称队员2 编号队员_群昵称.1队员3 编号队员_群昵称.2...队员6 编号队员_群昵称.5队员7 编号队员_群昵称.6队员8 编号队员_群昵称.7队员9 编号队员_群昵称.8队员10编号队员_群昵称.9
0Pandas数据分析你说的都对队5.0山枫叶纷飞6.07.0安慕希8.0信仰...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1Pandas数据分析熊猫人175.0鱼呲呲44.0Heaven37.0吕青50.0余柳成荫...25.0Never say never55.0K120.0Y.28.0X.Y.Q151.0swrong
2Pandas数据分析中国移不动107.0Y's124.0

标签:进阶,队员,res,昵称,df2,County,期中,编号,pandas
来源: https://blog.csdn.net/qq_32844743/article/details/112077650