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
NameSubjectGrade
0San ZhangChinese80
1San ZhangChinese90
2San ZhangMath100
3San ZhangMath90
4Si LiChinese70
5Si LiChinese80
6Si LiMath85

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

df.pivot_table(index = 'Name',
               columns = 'Subject',
               values = 'Grade',
               aggfunc = 'mean')
SubjectChineseMath
Name
San Zhang8595
Si Li7590
df.pivot_table(index = 'Name',
               columns = 'Subject',
               values = 'Grade',
               aggfunc = lambda x:x.mean())
SubjectChineseMath
Name
San Zhang8595
Si Li7585

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

df.pivot_table(index = 'Name',
               columns = 'Subject',
               values = 'Grade',
               aggfunc='mean',
               margins=True)
SubjectChineseMathAll
Name
San Zhang8595.00000090.000000
Si Li7585.00000078.333333
All8091.66666785.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
ClassNameChineseMath
01San Zhang8080
12Si Li9075
df_melted = df.melt(id_vars = ['Class', 'Name'],
                    value_vars = ['Chinese', 'Math'],
                    var_name = 'Subject',
                    value_name = 'Grade')
df_melted
ClassNameSubjectGrade
01San ZhangChinese80
12Si LiChinese90
21San ZhangMath80
32Si LiMath75

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

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

df_unmelted = df_melted.pivot(index = ['Class', 'Name'],
                              columns='Subject',
                              values='Grade')
df_unmelted # 下面需要恢复索引,并且重命名列索引名称
SubjectChineseMath
ClassName
1San Zhang8080
2Si Li9075
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()
FreshmanJuniorSeniorSophomore
01000
11000
20010
30001
40001

四、练习

Ex1:美国非法药物数据集

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

df = pd.read_csv('../data/drugs.csv').sort_values(['State','COUNTY','SubstanceName'],ignore_index=True)
df.head(3)
YYYYStateCOUNTYSubstanceNameDrugReports
02011KYADAIRBuprenorphine3
12012KYADAIRBuprenorphine5
22013KYADAIRBuprenorphine4

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

tmp = df.pivot(index=['State', 'COUNTY', 'SubstanceName'], 
        columns='YYYY',
        values='DrugReports')
tmp = tmp.reset_index().rename_axis(columns={'YYYY':''})
tmp.head()
StateCOUNTYSubstanceName20102011201220132014201520162017
0KYADAIRBuprenorphineNaN3.05.04.027.05.07.010.0
1KYADAIRCodeineNaNNaN1.0NaNNaNNaNNaN1.0
2KYADAIRFentanylNaNNaN1.0NaNNaNNaNNaNNaN
3KYADAIRHeroinNaNNaN1.02.0NaN1.0NaN2.0
4KYADAIRHydrocodone6.09.010.010.09.07.011.03.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()
StateCOUNTYSubstanceNameYYYYDrugReports
4KYADAIRHydrocodone20106.0
6KYADAIRMethadone20101.0
13KYALLENHydrocodone201010.0
15KYALLENMethadone20104.0
17KYALLENOxycodone201015.0
..................
49702WVWOODHydrocodone20178.0
49704WVWOODIsobutyryl fentanyl20173.0
49707WVWOODOxycodone20171.0
49708WVWOODTramadol20173.0
49709WVWYOMINGBuprenorphine20171.0

24062 rows × 5 columns

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值