pandas-task05.md

变型

为什么要变型?
在不同的场景下我们可能需要不同形式的数据,以便更好地展示。如练习1中的数据除了年份其余大部分数据都是相似的,将不同的年份细分可以减少大量重复信息,数据也更直观。

一、长宽表的变形

什么是长表?什么是宽表?这个概念是对于某一个特征而言的。例如:一个表中把性别存储在某一个列中,那么它就是关于性别的长表;如果把性别作为列名,列中的元素是某一其他的相关特征数值,那么这个表是关于性别的宽表。
pandas 针对长宽表的变形操作设计了一些有关的变形函数。

1. pivot-长变宽

将某一列中每个不同的元素都转换成一个新的列
pivot三元素
在这里插入图片描述
需满足唯一性,即index和cloumns组合必须唯一.
多级索引,传入列表即可

ClassNameExaminationSubjectGraderank
01San ZhangMidChinese8010
11San ZhangFinalChinese7515
22Si LiMidChinese8521
32Si LiFinalChinese6515
41San ZhangMidMath9020
51San ZhangFinalMath857
62Si LiMidMath926
72Si LiFinalMath882
#现在想要把测试类型和科目联合组成的四个类别(期中语文、期末语文、期中数学、期末数学)转到列索引,并且同时统计成绩和排名:
df.pivot(index=['Class','Name'],
			columns=['Subject','Examination'],
			values=['Grade','rank'])

在这里插入图片描述
在这里插入图片描述

2. pivot_table

pivot必须满足唯一性,不满足唯一性的时候就不能使用,例如,张三和李四都参加了两次语文考试和数学考试,按照学院规定,最后的成绩是两次考试分数的平均值,此时就无法通过 pivot 函数来完成,所以有了pivot_table。

NameSubjectGrade
0San ZhangChinese80
1San ZhangChinese90
2San ZhangMath100
3San ZhangMath90
4Si LiChinese70
5Si LiChinese80
6Si LiMath85
7Si LiMath95

比如上图,张三和李四都考了两次语文和数学,需要统计每次考的分数较高的作为最终成绩,可以按下面方法实现,aggfunc是聚合函数,可以用到上节记录分组中的聚合的所有适应聚合函数的方法。

df2=df.pivot_table(index='Name',
				columns='Subject',
				values='Grade',
				aggfunc='max')
print(df2.to_markdown())
NameChineseMath
San Zhang90100
Si Li8095

下面是使用聚合函数分别算平均和最大分数。
margin=True时统计所有情况(行、列),所用函数和聚合函数内一致。

df2=df.pivot_table(index='Name',
					columns='Subject',values='Grade',
					aggfunc=['max','mean'],
					margins='True')
Name(‘max’, ‘Chinese’)(‘max’, ‘Math’)(‘max’, ‘All’)(‘mean’, ‘Chinese’)(‘mean’, ‘Math’)(‘mean’, ‘All’)
San Zhang90100100859590
Si Li809595759082.5
All901001008092.586.25

3. melt-宽变长

和pivot相反,将宽表变为长表。

ClassNameChineseMath
01San Zhang8080
12Si Li9075
df_melted=df.melt(id_vars = ['Class', 'Name'],
       value_vars = ['Chinese', 'Math'],
       var_name = 'Subject',
       value_name = 'Grade')
print(df_melted.to_markdown())
ClassNameSubjectGrade
01San ZhangChinese80
12Si LiChinese90
21San ZhangMath80
32Si LiMath75

在这里插入图片描述
melt和pivot相互转换后恢复成原表:

df_unmelted = df_melted.pivot(index = ['Class', 'Name'],
                               columns='Subject',
                               values='Grade')
df_unmelted=df_unmelted.reset_index().rename_axis(
						columns={'Subject':''})

4. wide_to_long

melt的宽变长只能多列变成一个列,但是实际场景中很可能需要变成好几列。是否可以用多次melt?

ClassNameChinese_MidMath_MidChinese_FinalMath_Final
01San Zhang80908090
12Si Li75857585

试验了下通过两次melt将原表格四种成绩转成两种:语文和数学,但是再继续操作就不太方便了。

df_melted=df.melt(id_vars = ['Class', 'Name','Math_Mid','Math_Final'],
       value_vars = ['Chinese_Mid', 'Chinese_Final',],
       var_name = 'Subject_Chinese',
       value_name = 'Chinese_Grade')
df_melted2=df_melted.melt(id_vars = ['Class', 'Name','Subject_Chinese','Chinese_Grade'],
       value_vars = ['Math_Mid', 'Math_Final',],
       var_name = 'Subject_Math',
       value_name = 'Math_Grade')
df_melted2
ClassNameSubject_ChineseChinese_GradeSubject_MathMath_Grade
01San ZhangChinese_Mid80Math_Mid90
12Si LiChinese_Mid75Math_Mid85
21San ZhangChinese_Final80Math_Mid90
32Si LiChinese_Final75Math_Mid85
41San ZhangChinese_Mid80Math_Final90
52Si LiChinese_Mid75Math_Final85
61San ZhangChinese_Final80Math_Final90
72Si LiChinese_Final75Math_Final85

使用wid_to_long()

df_wtl=pd.wide_to_long(df,stubnames=['Chinese', 'Math'],
                    i = ['Class', 'Name'],
                    j='Examination',
                    sep='_',
                    suffix='.+')
print(df_wtl.to_markdown())
ChineseMath
(1, ‘San Zhang’, ‘Mid’)8090
(1, ‘San Zhang’, ‘Final’)8191
(2, ‘Si Li’, ‘Mid’)7585
(2, ‘Si Li’, ‘Final’)7684

在这里插入图片描述

二、索引的变形

1. stack与unstack

之前学到了swaplevel 或者 reorder_levels 进行索引内部的层交换,行列索引之间 的交换需要使用stack和unstack,它们都属于某一列或几列 元素 和 列索引 之间的转换,而不是索引之间的转换。

unstack-行索引变列索引

每次unstack前须保持每次最里两层行索引的组合是唯一的(唯一性)

col_1col_2
(‘A’, ‘cat’, ‘big’)11
(‘A’, ‘dog’, ‘small’)11
(‘B’, ‘cat’, ‘big’)11
(‘B’, ‘dog’, ‘small’)11

一次unpack之后

df=df.unstack()
print(df.to_markdown())
(‘col_1’, ‘big’)(‘col_1’, ‘small’)(‘col_2’, ‘big’)(‘col_2’, ‘small’)
(‘A’, ‘cat’)1nan1nan
(‘A’, ‘dog’)nan1nan1
(‘B’, ‘cat’)1nan1nan
(‘B’, ‘dog’)nan1nan1

两次之后

(‘col_1’, ‘big’, ‘cat’)(‘col_1’, ‘big’, ‘dog’)(‘col_1’, ‘small’, ‘cat’)(‘col_1’, ‘small’, ‘dog’)(‘col_2’, ‘big’, ‘cat’)(‘col_2’, ‘big’, ‘dog’)(‘col_2’, ‘small’, ‘cat’)(‘col_2’, ‘small’, ‘dog’)
A1nannan11nannan1
B1nannan11nannan1

每次unstack都会将最里层的行索引转换成列索引。
个人思考:
惊奇地发现进行2(k+1)次unstack后会恢复原状,k是行索引的层数,如果行索引有k层(比如k=3),那么第k=3次unstack后DataFrame会变成Series,第k+1次后会变回DataFrame,不过和原始的表格行列完全相反,继续k次unstack又变成Series,此时再unstack即可变成和原始表格几乎一致的情况,不过这么多次unstack后会产生一些NA值,试了一下dropNa之后和原表格一致。

stack-列索引变行索引

和unpack刚好相反,用法和注意事项完全一致,这里不多描写。

2. 聚合与变形的关系

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

总结:变型一般只改变呈现形式,不改变个数和数值。聚合会改变。

三、其他变形函数

1. crosstab

crosstab 并不是一个值得推荐使用的函数,因为它能实现的所有功能 pivot_table 都能完成,并且速度更快。在默认状态下, crosstab 可以统计元素组合出现的频数,即 count 操作。

2. explode

explode 参数能够对某一列的元素进行纵向的展开,被展开的单元格必须存储 list, tuple, Series, np.ndarray 中的一种类型。
如图,指定A列展开,将A列第一行列表及第三行Series展开,A列展开的时候B列不操作。
在这里插入图片描述
B列展开的时候A列不操作。
在这里插入图片描述

3.get_dummies

get_dummies 是用于特征构建的重要函数之一,其作用是把类别特征转为指示变量。例如,对年级一列转为指示变量,属于某一个年级的对应列标记为1,否则为0:

SchoolGradeNameGenderHeightWeightTransferTest_NumberTest_DateTime_Record
0Shanghai Jiao Tong UniversityFreshmanGaopeng YangFemale158.946N12019/10/50:04:34
1Peking UniversityFreshmanChangqiang YouMale166.570N12019/9/40:04:20
2Shanghai Jiao Tong UniversitySeniorMei SunMale188.989N22019/9/120:05:22
res=pd.get_dummies(df.Grade).head()
print(res.to_markdown())
FreshmanJuniorSeniorSophomore
01000
11000
20010
30001
40001

四、练习

Ex1:美国非法药物数据集

在这里插入图片描述
1.

#长变宽 满足唯一性 使用pivot
df2=df.pivot(index=['State','COUNTY','SubstanceName'],
				columns='YYYY',values=['DrugReports'])
df2.head(3)

忘记重新设置index.

df2=df.pivot(index=['State','COUNTY','SubstanceName'],
			columns='YYYY',
			values='DrugReports').reset_index().rename_axis(
			columns={'YYYY':''})

  1. 恢复为原表 使用melt ,变换之后要将NA值丢弃,不然无法转换格式
df_melted=df2.melt(id_vars = ['State','COUNTY','SubstanceName'],
                        value_vars =  [i for i in range(2010,2018)],
#                         value_vars = df2.columns[-8:],
                        var_name = 'YYYY',
                        value_name = 'DrugReports').dropna(
                        subset=['DrugReports'])
df_melted.head(3)

第一种方法pivot_table

df1=df.pivot_table(index='YYYY', columns='State',
              values='DrugReports', aggfunc='sum')

res=df1.rename_axis(index={'YYYY':''})
print(res.head().to_markdown())
KYOHPAVAWV
201010453197071981486852890
201110289203301998767493271
201210722231451995978313376
2013111482684620409116754046
201411081308602490490373280

第二种方法groupby+unpack

df2 = df.groupby(['State', 'YYYY'])['DrugReports'].sum(
    ).to_frame().unstack(0).droplevel(0,axis=1)
print(df2.head().to_markdown())
YYYYKYOHPAVAWV
201010453197071981486852890
201110289203301998767493271
201210722231451995978313376
2013111482684620409116754046
201411081308602490490373280

Ex2:特殊的wide_to_long方法

在这里插入图片描述
对列名进行修改,在进行wide_to_long即可。
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值