pandas-task05.md

文章目录

  • 变型
    • 一、长宽表的变形
      • 1. pivot-长变宽
      • 2. pivot_table
      • 3. melt-宽变长
      • 4. wide_to_long
    • 二、索引的变形
      • 1. stack与unstack
        • unstack-行索引变列索引
        • stack-列索引变行索引
      • 2. 聚合与变形的关系
    • 三、其他变形函数
      • 1. crosstab
      • 2. explode
      • 3.get_dummies
    • 四、练习
      • Ex1:美国非法药物数据集
      • Ex2:特殊的wide_to_long方法

变型

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

一、长宽表的变形

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

1. pivot-长变宽

将某一列中每个不同的元素都转换成一个新的列
pivot三元素
pandas-task05.md_第1张图片
需满足唯一性,即index和cloumns组合必须唯一.
多级索引,传入列表即可

Class Name Examination Subject Grade rank
0 1 San Zhang Mid Chinese 80 10
1 1 San Zhang Final Chinese 75 15
2 2 Si Li Mid Chinese 85 21
3 2 Si Li Final Chinese 65 15
4 1 San Zhang Mid Math 90 20
5 1 San Zhang Final Math 85 7
6 2 Si Li Mid Math 92 6
7 2 Si Li Final Math 88 2
#现在想要把测试类型和科目联合组成的四个类别(期中语文、期末语文、期中数学、期末数学)转到列索引,并且同时统计成绩和排名:
df.pivot(index=['Class','Name'],
			columns=['Subject','Examination'],
			values=['Grade','rank'])

pandas-task05.md_第2张图片
pandas-task05.md_第3张图片

2. pivot_table

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

Name Subject Grade
0 San Zhang Chinese 80
1 San Zhang Chinese 90
2 San Zhang Math 100
3 San Zhang Math 90
4 Si Li Chinese 70
5 Si Li Chinese 80
6 Si Li Math 85
7 Si Li Math 95

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

df2=df.pivot_table(index='Name',
				columns='Subject',
				values='Grade',
				aggfunc='max')
print(df2.to_markdown())
Name Chinese Math
San Zhang 90 100
Si Li 80 95

下面是使用聚合函数分别算平均和最大分数。
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 Zhang 90 100 100 85 95 90
Si Li 80 95 95 75 90 82.5
All 90 100 100 80 92.5 86.25

3. melt-宽变长

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

Class Name Chinese Math
0 1 San Zhang 80 80
1 2 Si Li 90 75
df_melted=df.melt(id_vars = ['Class', 'Name'],
       value_vars = ['Chinese', 'Math'],
       var_name = 'Subject',
       value_name = 'Grade')
print(df_melted.to_markdown())
Class Name Subject Grade
0 1 San Zhang Chinese 80
1 2 Si Li Chinese 90
2 1 San Zhang Math 80
3 2 Si Li Math 75

pandas-task05.md_第4张图片
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?

Class Name Chinese_Mid Math_Mid Chinese_Final Math_Final
0 1 San Zhang 80 90 80 90
1 2 Si Li 75 85 75 85

试验了下通过两次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
Class Name Subject_Chinese Chinese_Grade Subject_Math Math_Grade
0 1 San Zhang Chinese_Mid 80 Math_Mid 90
1 2 Si Li Chinese_Mid 75 Math_Mid 85
2 1 San Zhang Chinese_Final 80 Math_Mid 90
3 2 Si Li Chinese_Final 75 Math_Mid 85
4 1 San Zhang Chinese_Mid 80 Math_Final 90
5 2 Si Li Chinese_Mid 75 Math_Final 85
6 1 San Zhang Chinese_Final 80 Math_Final 90
7 2 Si Li Chinese_Final 75 Math_Final 85

使用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())
Chinese Math
(1, ‘San Zhang’, ‘Mid’) 80 90
(1, ‘San Zhang’, ‘Final’) 81 91
(2, ‘Si Li’, ‘Mid’) 75 85
(2, ‘Si Li’, ‘Final’) 76 84

pandas-task05.md_第5张图片

二、索引的变形

1. stack与unstack

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

unstack-行索引变列索引

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

col_1 col_2
(‘A’, ‘cat’, ‘big’) 1 1
(‘A’, ‘dog’, ‘small’) 1 1
(‘B’, ‘cat’, ‘big’) 1 1
(‘B’, ‘dog’, ‘small’) 1 1

一次unpack之后

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

两次之后

(‘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’)
A 1 nan nan 1 1 nan nan 1
B 1 nan nan 1 1 nan nan 1

每次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列不操作。
pandas-task05.md_第6张图片
B列展开的时候A列不操作。
pandas-task05.md_第7张图片

3.get_dummies

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

School Grade Name Gender Height Weight Transfer Test_Number Test_Date Time_Record
0 Shanghai Jiao Tong University Freshman Gaopeng Yang Female 158.9 46 N 1 2019/10/5 0:04:34
1 Peking University Freshman Changqiang You Male 166.5 70 N 1 2019/9/4 0:04:20
2 Shanghai Jiao Tong University Senior Mei Sun Male 188.9 89 N 2 2019/9/12 0:05:22
res=pd.get_dummies(df.Grade).head()
print(res.to_markdown())
Freshman Junior Senior Sophomore
0 1 0 0 0
1 1 0 0 0
2 0 0 1 0
3 0 0 0 1
4 0 0 0 1

四、练习

Ex1:美国非法药物数据集

pandas-task05.md_第8张图片
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())
KY OH PA VA WV
2010 10453 19707 19814 8685 2890
2011 10289 20330 19987 6749 3271
2012 10722 23145 19959 7831 3376
2013 11148 26846 20409 11675 4046
2014 11081 30860 24904 9037 3280

第二种方法groupby+unpack

df2 = df.groupby(['State', 'YYYY'])['DrugReports'].sum(
    ).to_frame().unstack(0).droplevel(0,axis=1)
print(df2.head().to_markdown())
YYYY KY OH PA VA WV
2010 10453 19707 19814 8685 2890
2011 10289 20330 19987 6749 3271
2012 10722 23145 19959 7831 3376
2013 11148 26846 20409 11675 4046
2014 11081 30860 24904 9037 3280

Ex2:特殊的wide_to_long方法

pandas-task05.md_第9张图片
对列名进行修改,在进行wide_to_long即可。
pandas-task05.md_第10张图片

你可能感兴趣的:(pandas,python,pandas)