Pandas进阶伍 变形

Pandas进阶伍 变形

pandas进阶系列根据datawhale远昊大佬的joyful pandas教程写一些自己的心得和补充,本文部分引用了原教程,并参考了《利用Python进行数据分析》、pandas官网

另注:本文是对joyful pandas教程的延伸,完整理解需先阅读joyful pandas教程第五章

目前的进度:学完了内容,做了一个练一练和ex1前两问,都有解决过程,28号早上补完剩余的习题

import numpy as np
import pandas as pd

1. pivot

pivot是一种典型的长表变宽表的函数,首先来看一个例子:下表存储了张三和李四的语文和数学分数,现在想要把语文和数学分数作为列来展示。

【练一练】

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

【我的思路】

不一定成立,题目中原本给的数据构造的比较均匀,每人每科刚好都有两个数据,因此造成了边际表的值是均值聚合后的表的行列的均值的假象。
实际上边际表的值还是按照原表的值计算的,下面我更改了原数据(删除了一行数据使其不均匀),就可以看到汇总后的表和原表值不同

df = pd.DataFrame({
     'Name':['San Zhang', 'San Zhang', 
                              'San Zhang', 'San Zhang',
                              'Si Li', 'Si Li', 'Si Li', ],
                   'Subject':['Chinese', 'Chinese', 'Math', 'Math',
                                 'Chinese', 'Chinese', 'Math'],
                   'Grade':[80, 90, 100, 90, 70, 80, 85]})
df
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

pandas中提供了pivot_table来实现,其中的aggfunc参数就是使用的聚合函数。上述场景可以如下写出:

df.pivot_table(index = 'Name',
               columns = 'Subject',
               values = 'Grade',
               aggfunc = 'mean')
Subject Chinese Math
Name
San Zhang 85 95
Si Li 75 90
df.pivot_table(index = 'Name',
               columns = 'Subject',
               values = 'Grade',
               aggfunc = lambda x:x.mean())
Subject Chinese Math
Name
San Zhang 85 95
Si Li 75 85

此外,pivot_table具有边际汇总的功能,可以通过设置margins=True来实现,其中边际的聚合方式与aggfunc中给出的聚合方法一致。下面就分别统计了语文均分和数学均分、张三均分和李四均分,以及总体所有分数的均分:

df.pivot_table(index = 'Name',
               columns = 'Subject',
               values = 'Grade',
               aggfunc='mean',
               margins=True)
Subject Chinese Math All
Name
San Zhang 85 95.000000 90.000000
Si Li 75 85.000000 78.333333
All 80 91.666667 85.000000

可以看到,上面这个表中(75+85)/2 != 78.3 因此,边际表是按原表计算的,不是按聚合后的表计算的

【练一练END】

3. melt

长宽表只是数据呈现方式的差异,但其包含的信息量是等价的,前面提到了利用pivot把长表转为宽表,那么就可以通过相应的逆操作把宽表转为长表,melt函数就起到了这样的作用。在下面的例子中,Subject以列索引的形式存储,现在想要将其压缩到一个列中。

df = pd.DataFrame({
     'Class':[1,2],
                   'Name':['San Zhang', 'Si Li'],
                   'Chinese':[80, 90],
                   'Math':[80, 75]})
df
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')
df_melted
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

melt的主要参数和压缩的过程如下图所示:

前面提到了meltpivot是一组互逆过程,那么就一定可以通过pivot操作把df_melted转回df的形式:

df_unmelted = df_melted.pivot(index = ['Class', 'Name'],
                              columns='Subject',
                              values='Grade')
df_unmelted # 下面需要恢复索引,并且重命名列索引名称
Subject Chinese Math
Class Name
1 San Zhang 80 80
2 Si Li 90 75
df_unmelted = df_unmelted.reset_index().rename_axis(columns={
     'Subject':''})
df_unmelted.equals(df)
True

3. get_dummies

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

pd.get_dummies(df.Grade).head()
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:美国非法药物数据集

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

df = pd.read_csv('../data/drugs.csv').sort_values(['State','COUNTY','SubstanceName'],ignore_index=True)
df.head(3)
YYYY State COUNTY SubstanceName DrugReports
0 2011 KY ADAIR Buprenorphine 3
1 2012 KY ADAIR Buprenorphine 5
2 2013 KY ADAIR Buprenorphine 4

第一问:我的思路是首先可以确定是长变宽,所以要用pivot,利用前面的带颜色的分割图,在结果图中也分色块展示一下,目标的结果如图所示,所以就确定了参数分别应该选哪几列。
Pandas进阶伍 变形_第1张图片

tmp = df.pivot(index=['State', 'COUNTY', 'SubstanceName'], 
        columns='YYYY',
        values='DrugReports')
tmp = tmp.reset_index().rename_axis(columns={
     'YYYY':''})
tmp.head()
State COUNTY SubstanceName 2010 2011 2012 2013 2014 2015 2016 2017
0 KY ADAIR Buprenorphine NaN 3.0 5.0 4.0 27.0 5.0 7.0 10.0
1 KY ADAIR Codeine NaN NaN 1.0 NaN NaN NaN NaN 1.0
2 KY ADAIR Fentanyl NaN NaN 1.0 NaN NaN NaN NaN NaN
3 KY ADAIR Heroin NaN NaN 1.0 2.0 NaN 1.0 NaN 2.0
4 KY ADAIR Hydrocodone 6.0 9.0 10.0 10.0 9.0 7.0 11.0 3.0
tmp.columns[-8:]
Index([2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017], dtype='object', name='')

第二问:这里发现一个神奇的事,上一问的2010,2011这些列,竟然不是字符串表示的,而是数字表示的

tmp.melt(id_vars=['State', 'COUNTY', 'SubstanceName'],
        value_vars=list(range(2010, 2018)),
        var_name='YYYY',
        value_name='DrugReports').dropna()
State COUNTY SubstanceName YYYY DrugReports
4 KY ADAIR Hydrocodone 2010 6.0
6 KY ADAIR Methadone 2010 1.0
13 KY ALLEN Hydrocodone 2010 10.0
15 KY ALLEN Methadone 2010 4.0
17 KY ALLEN Oxycodone 2010 15.0
... ... ... ... ... ...
49702 WV WOOD Hydrocodone 2017 8.0
49704 WV WOOD Isobutyryl fentanyl 2017 3.0
49707 WV WOOD Oxycodone 2017 1.0
49708 WV WOOD Tramadol 2017 3.0
49709 WV WYOMING Buprenorphine 2017 1.0

24062 rows × 5 columns

你可能感兴趣的:(pandas,datawhale,数据分析,大数据,pandas)