Task05|joyfulpandas|变形

元素和列索引之间的转换

1. pivot(长表变宽)

  • index 变形后的行索引
  • columns 需要转到列索引的列
  • values 数值
df = pd.DataFrame({'Class':[2,2,1,1],
                   'Name':['San Zhang','San Zhang','Si Li','Si Li'],
                   'Subject':['Chinese','Math','Chinese','Math'],
                   'Grade':[80,75,90,85]})
df.loc[1,'Subject']='Chinese'
try:
	df.pivot(index='Name',columns='Subject',values='Grade')
except Exception as e:
	Err_Msg=e

df = pd.DataFrame({'Class':[1, 1, 2, 2, 1, 1, 2, 2],
                   'Name':['San Zhang', 'San Zhang', 'Si Li', 'Si Li',
                              'San Zhang', 'San Zhang', 'Si Li', 'Si Li'],
                   'Examination': ['Mid', 'Final', 'Mid', 'Final',
                                    'Mid', 'Final', 'Mid', 'Final'],
                   'Subject':['Chinese', 'Chinese', 'Chinese', 'Chinese',
                                 'Math', 'Math', 'Math', 'Math'],
                   'Grade':[80, 75, 85, 65, 90, 85, 92, 88],
                   'rank':[10, 15, 21, 15, 20, 7, 6, 2]})
pivot_multi= df.pivot(index = ['Class', 'Name'],
                       columns = ['Subject','Examination'],
                       values = ['Grade','rank'])

  • 唯一性要求
    原表中的index和columns对应两个列的行组合必须唯一
    pivot 会返回多级索引
    在这里插入图片描述

2. pivot_table

pivot的使用依赖于唯一性条件
不满足唯一性条件必须通过聚合操作使得相同行列组合对应的多个值变为一个值

  • aggfunc 使用聚合函数 aggfunc参数可以计入上一章所有的合法聚合字符串
    可以传入序列为输入,列表为输出的聚合函数
  • margins=True 边际汇总 (合计)
df = pd.DataFrame({'Name':['San Zhang', 'San Zhang', 
                              'San Zhang', 'San Zhang',
                              'Si Li', 'Si Li', 'Si Li', 'Si Li'],
                   'Subject':['Chinese', 'Chinese', 'Math', 'Math',
                                 'Chinese', 'Chinese', 'Math', 'Math'],
                   'Grade':[80, 90, 100, 90, 70, 80, 85, 95]})
df.pivot_table(index='Name',columns='Subject',values='Grade',aggfunc='mean')
df.pivot_table(index='Name',columns='Subject',values='Grade',aggfunc=lambda x:x.mean())
【练一练】

在上面的边际汇总例子中,行或列的汇总为新表中行元素或者列元素的平均值,而总体的汇总为新表中四个元素的平均值。这种关系一定成立吗?若不成立,请给出一个例子来说明。

#假设Lisi 多加一项数学的成绩
df =pd.DataFrame({'Name':['San Zhang', 'San Zhang', 
                              'San Zhang', 'San Zhang',
                              'Si Li', 'Si Li', 'Si Li', 'Si Li','Si Li'],
                   'Subject':['Chinese', 'Chinese', 'Math', 'Math',
                                 'Chinese', 'Chinese', 'Math', 'Math','Math'],
                   'Grade':[80, 90, 100, 90, 70, 80, 85, 95,91]})
df.pivot_table(index='Name',columns='Subject',values='Grade',aggfunc='mean', margins=True)

在这里插入图片描述

可以看到lisi的数学平均分:(85+95+91)/3=90.3333
(85+95)/2=90
这导致了总均分统计的时候All=(95+91+85+70+80)/5=84.2

3. melt 逆操作把宽表转为长表

id_vars:列变量
在下面的例子中,Subject以列索引的形式存储,现在想要将其压缩到一个列中。
需要从列压缩到行的变量:value_vars:[] -> 名字var_name
原来列变量值的含义:value_name:列变量值的名字

df=pd.DataFrame({'Class':[1,2],'Name':['San Zhang','Si Li'],
'Chinese':[80,90],'Math':[80,75]})
df_melted=df.melt(id_vars=['Class','Name'],value_vars=['Chinese','Math'],var_name='Subject',value_name='Grade')
#通过pivot转回df
df_unmelted=df_melted.pivot(index=['Class','Name'],columns='Subject',values='Grade')
#多了一个Subject,需要恢复索引
df_unmelted=df_unmelted.reset_index().rename_axis({'Subject':''})

在这里插入图片描述

4. wide_to_long(交叉列)

列中包含了交叉类别,比如math_mid,math_final这样的列

  • suffix 正则后缀
  • sep 分隔符
  • stubnames:变量值的含义,转化之后的表以其为列
  • i 保持不变的id变量,等价于melt中的id_vars
  • j 压缩到行的变量名含义,等价于melt中的var_name
df=pd.DataFrame({'Class':[1,2],'Name':['San Zhang','Si Li'],
'Chinese_Mid':[80,75],'Math_Mid':[90,85],
'Chinese_Final':[80,75],'Math_Final':[90,85]
})
pd.wide_to_long(df,stubnames=['Chinese','Nath'],i=['Class','Name'],j='Examination',sep='_',suffix='.+')

res=pivot_multi.copy()#
res.columns=res.columns.map(lambda x:'_'.join(x))
res=res.reset_index()#重置索引
res=pd.wide_to_long(res,stubnames=['Grade','rank'],i=['Class','Name'],
j='Subject_Examination',sep='_',suffix='.+')

res=res.reset_index()
res[['Subject','Examination']]=res['Subject_Examination'].str.split("_",expand=True)
res=res[['Class','Name','Examination', 'Subject', 'Grade', 'rank']].sort_values('Subject')
#sort_values根据某个字段进行排序
res=res.reset_index(drop=True)

  1. pivot_multi.copy() 使用拷贝函数深拷贝复制
  2. 改变索引名字 使用map+lambda函数
    string 有一个join函数
  3. str.split(“_”,expand=True)
    使用_进行分割,expand=True可以扩展
    可以使用这个函数进行列的分割
res.columns=res.columns.map(lambda x:'_'.join(x))

在这里插入图片描述

二、索引的变形

行列索引之间的变换

利用swaplevel或者reorder_levels进行索引内部的层交换

stack和unstack

属于某一列或几列 元素 \color{red}{元素} 元素 列索引 \color{red}{列索引} 列索引之间的转换,而不是索引之间的转换
unstack 将行索引转换为列索引

  • unstack的主要参数是移动的层号,默认转化最内层,移动到列索引的最内层,同时支持同时转化多个层
    最内层的是索引最大的
  • 唯一性要求
    保证被转为列索引的行索引层和被保留的行索引层构成的组合是唯一的
df=pd.DataFrame(np.ones((4,2)),
                  index = pd.Index([('A', 'cat', 'big'),
                                    ('A', 'dog', 'small'),
                                    ('B', 'cat', 'big'),
                                    ('B', 'dog', 'small')]),
                  columns=['col_1', 'col_2'])

df.unstack()
等同于
df.unstack(2)
#同时转化多层
df.unstack([0,2])

#唯一性证明
my_index=df.index.to_list()
my_index[1]=my_index[0]
df.index=pd.Index(my_index)#构造index
try:
	df.unstack()
except Exception as e:
	Err_Msg=e
Err_Msg	

在这里插入图片描述

stack 将列索引层压入行索引

df = pd.DataFrame(np.ones((4,2)),
                  index = pd.Index([('A', 'cat', 'big'),
                                    ('A', 'dog', 'small'),
                                    ('B', 'cat', 'big'),
                                    ('B', 'dog', 'small')]),
                  columns=['index_1', 'index_2']).T
df
df.stack()
df.stack([1,2])

在这里插入图片描述

2. 聚合与变形的关系

在上面介绍的所有函数中,除了带有聚合效果的pivot_table以外,所有的函数在变形前后并不会带来values个数的改变,只是这些值在呈现的形式上发生了变化。在上一章讨论的分组聚合操作,由于生成了新的行列索引,因此必然也属于某种特殊的变形操作,但由于聚合之后把原来的多个值变为了一个值,因此values的个数产生了变化,这也是分组聚合与变形函数的最大区别。

变形:呈现形式发生了变化
分组聚合:将原来多个值变成了一个值

三、其他变形函数

1. crosstab

pivot_table能完成crosstab的所有功能
cross能统计元素组合出现的频数.(count操作)

统计learn_pandas数据集中学校和转系情况对应的频数:

df=pd.read_csv('../data/learn_pandas.csv')
pd.crosstab(index=df.School,columns=df.Transfer)
#等价于
pd.crosstab(index=df.School,columns=df.Transfer,values=[0]*df.shape[0],aggfunc='count')
#等价于
df.pivot_table(index='School',columns='Transfer',values='Name',aggfuc='count')

在这里插入图片描述
两个函数的区别:
pivot_table传入的是被调用表对应的名字
crosstab的对应位置传入的是具体的序列

2. explode

explode参数能够对某一列的元素进行纵向的展开
被展开的单元格必须存储 中的一种类型

  1. list
  2. tuple
  3. Series
  4. np.ndarray
df_ex=pd.DataFrame({'A':[[1,2],'my_str',{1,2},pd.Series([3,4])]})
df_ex.explode('A')
#此时对应的行号不会变

在这里插入图片描述

3. get_dummies 转化为零一矩阵,特征构建

get_dummies是用于特征构建的重要函数之一,其作用是把类别特征转为指示变量。

pd.get_dummies(df.Grade).head()

四、练习

Ex1:美国非法药物数据集

现有一份关于美国非法药物的数据集,其中SubstanceName, DrugReports分别指药物名称和报告数量:

  1. 将数据转为如下的形式:
    在这里插入图片描述
df = pd.read_csv('../data/drugs.csv').sort_values(['State','COUNTY','SubstanceName'],ignore_index=True)
df.head(3)
df_1=df.pivot(index=['State','COUNTY','SubstanceName'],columns="YYYY",values='DrugReports')
df_1.reset_index().rename_axis(columns={'YYYY':''})

在这里插入图片描述

在这里插入图片描述

  1. 将第1问中的结果恢复为原表。
df_2=df_1.melt(id_vars=['State','COUNTY','SubstanceName'],
          value_vars=df_1.columns[3:],
          var_name='YYYY',value_name='DrugReports').dropna(subset=['DrugReports']).astype({'YYYY':'int64','DrugReports':'int64'})
df_2=df_2.sort_values(['State','COUNTY','SubstanceName'],ignore_index=True).reindex_like(df)
df_2.equals(df)
  1. State分别统计每年的报告数量总和,其中State, YYYY分别为列索引和行索引,要求分别使用pivot_table函数与groupby+unstack两种不同的策略实现,并体会它们之间的联系。
df_3=df_2.pivot_table(index='YYYY',columns='State',values='DrugReports',aggfunc='sum')
df_3.head()
df_4=df.groupby(['State','YYYY'])['DrugReports'].sum().to_frame()
df_4.head()
df_5=df_4.unstack(0).droplevel(0,axis=1)

Ex2:特殊的wide_to_long方法

从功能上看,melt方法应当属于wide_to_long的一种特殊情况,即stubnames只有一类。请使用wide_to_long生成melt一节中的df_melted。(提示:对列名增加适当的前缀)

df = pd.DataFrame({'Class':[1,2],
                   'Name':['San Zhang', 'Si Li'],
                   'Chinese':[80, 90],
                   'Math':[80, 75]})
df1=df.rename(columns={'Chinese':'pre_Chinese','Math':'pre_Math'})
pd.wide_to_long(df1,stubnames=['pre'],
i=['Class','Name']
j='subject',sep='_',suffix='.+').reset_index().rename(columns={'pre':'Grade'})
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值