前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Pandas进阶|数据透视表与逆透视

Pandas进阶|数据透视表与逆透视

作者头像
数据STUDIO
发布2021-09-26 14:37:06
4.2K0
发布2021-09-26 14:37:06
举报
文章被收录于专栏:数据STUDIO

数据透视表将每一列数据作为输入,输出将数据不断细分成多个维度累计信息的二维数据表。在实际数据处理过程中,数据透视表使用频率相对较高,今天云朵君就和大家一起学习pandas数据透视表与逆透视的使用方法。

本次使用的数据来源于Kaggle,车辆被警察拦下并进行搜查记录数据集,简称车辆数据。文末有下载方式,大家按需获取。

数据基本情况

groupby数据透视表

使用 pandas.DataFrame.groupby 函数,其原理如下图所示。

使用车辆数据集统计不同性别司机的平均年龄,聚合后用二维切片可以输出DataFrame数据框。

代码语言:javascript
复制
data.groupby('driver_gender'
            )[['driver_age']].mean()

在聚合后一维切片会得到 pandas.Series.

代码语言:javascript
复制
data.groupby('driver_gender'
            )['driver_age'].mean()
代码语言:javascript
复制
driver_gender
F    32.607399
M    34.537886
Name: driver_age, dtype: float64

可能还想进一步探索,同时观察不同司机性别与司机种族的平均年龄。根据 GroupBy 的操作流程,我们也许能够实现想要的结果:将司机种族('driver_race')与司机性别('driver_gender')分组,然后选择司机年龄('driver_age')列,应用均值('mean')累计函数,再将各组结果组合,最后通过行索引转列索引操作将最里层的行索引转换成列索引,形成二维数组。

代码语言:javascript
复制
data.groupby(['driver_gender',
              'driver_race']
              )[['driver_age']].aggregate('mean')
通过unstack重排数据表

如果原表只有一级索引,unstack就将每一个列都分出来,然后全部纵向叠加在一起,每一个列名作为新的一级索引,原本的索引作为二级索引。如果原表有二级索引,那么unstack就会将二级索引作为新的列名,一级索引作为新的索引。

代码语言:javascript
复制
data.groupby(['driver_gender', 
              'driver_race']
            )[['driver_age']].aggregate('mean').unstack()

pivot_table

虽然这样就可以更清晰地观察出不同司机性别与司机种族的平均年龄,但代码有点复杂。要理解这个长长的语句可不是那么容易的事。

由于二维的 GroupBy 应用场景非常普遍,因此 Pandas 提供了一个快捷方式 pivot_table 来快速解决多维的累计分析任务。

pivot_table()的参数 values 待聚合的列的名称。默认聚合所有数值列 index 用于分组的列名或其他分组键,出现在结果透视表的行 columns 用于分组的列名或其他分组键,出现在结果透视表的列 aggfunc 聚合函数或函数列表,默认为'mean'。可以使任何对groupby有效的函数 fill_value 用于替换结果表中的缺失值 dropna 默认为True margins_name 默认为'ALL',当参数margins为True时,ALL行和列的名字

同样是上面的需求,同时观察不同司机性别与司机种族的平均年龄 ,用pivot_table实现透视表。

代码语言:javascript
复制
data.pivot_table(values='driver_age', 
                 index='driver_gender', 
                 columns='driver_race')

多级数据透视表

与 GroupBy 类似,数据透视表中的分组也可以通过各种参数指定多个等级。

行索引和列索引都可以再设置为多层,不过行索引和列索引在本质上是一样的,大家需要根据实际情况合理布局。

代码语言:javascript
复制
data.pivot_table(values='driver_age', 
                 index=['driver_gender',
                        'stop_duration'], 
                 columns='driver_race')

自定义聚合函数

aggfunc 参数用于设置累计函数类型,默认值是均值(mean)。累计函数可以用一些常见的字符串 ('sum'、'mean'、'count'、'min'、'max' 等)表示,也可以用标准的累计函数(np.sum()、min()、sum() 等)。

还可以通过字典为不同的列指定不同的累计函数。

  • 如果传入参数为list,则每个聚合函数对每个列都进行一次聚合。
  • 如果传入参数为dict,则每个列仅对其指定的函数进行聚合, 此时values参数可以不传。
代码语言:javascript
复制
data.pivot_table(index='driver_gender', 
                 columns='driver_race',
                 aggfunc={'driver_age':'mean', 
                          'violation':'count'})

这里没有使用参数 values。其实在我们通过字典为 aggfunc 指定映射关系的时候,待透视的数值就已经确定了。

margin 的标签可以通过 margins_name 参数进行自定义, 默认值是 "All"。

下面按行、按列进行汇总,指定汇总列名为“Total”

代码语言:javascript
复制
data.pivot_table(index="driver_gender", 
                 columns="driver_race",
                 values="violation", 
                 aggfunc= "count",
                 margins=True, 
                 margins_name="Total")

pandas.crosstab

crosstab 是交叉表,是一种特殊的数据透视表默认是计算分组频率的特殊透视表(默认的聚合函数是统计行列组合出现的次数)。如果指定了聚合函数则按聚合函数来统计,但是要指定values的值,指明需要聚合的数据。

pandas.crosstab 参数 index:指定了要分组的列,最终作为行。 columns:指定了要分组的列,最终作为列。 values:指定了要聚合的值(由行列共同影响),需要指定aggfunc参数。 rownames:指定了行名称。 colnames:指定了列名称。 aggfunc:指定聚合函数。必须指定values的值。 margins:布尔值,是否分类统计。默认False。 margins_name:分类统计的名称,默认是"All"。 dropna:是否包含全部是NaN的列。默认是True。

代码语言:javascript
复制
pd.crosstab(index=data.driver_gender, 
            columns=data.driver_race, 
            margins=True)

逆透视

如果说 df.pivot()将长数据集转换成宽数据集,df.melt() 则是将宽数据集变成长数据集 melt() 既是顶级类函数也是实例对象函数,作为类函数出现时,需要指明 DataFrame 的名称

pd.melt 参数 frame 被 melt 的数据集名称在 pd.melt() 中使用 id_vars 不需要被转换的列名,在转换后作为标识符列(不是索引列) value_vars 需要被转换的现有列,如果未指明,除 id_vars 之外的其他列都被转换 var_name 自定义列名名称,设置由 'value_vars' 组成的新的 column name value_name 自定义列名名称,设置由 'value_vars' 的数据组成的新的 column name col_level 如果列是MultiIndex,则使用此级别

代码语言:javascript
复制
df = data.loc[:,['driver_gender', 
                 'driver_race', 
                 'violation']]
df
代码语言:javascript
复制
df_pivot = data.pivot_table(index="driver_gender", 
                      columns="driver_race",
                      values="violation", 
                      aggfunc= "count")
df_pivot

为方便下面转换的理解,经过去除columns的name后得到:

下面开始进行转换。保留"driver_gender",对剩下列全部转换,并给设置对列定义列名。

代码语言:javascript
复制
df_wide.melt(id_vars='driver_gender',
             var_name = 'driver_race',
             value_name='violation_count')

上述同样的结果用groupby也可以做到,如下所示。

代码语言:javascript
复制
df.groupby(['driver_gender',
            'driver_race']
          )[['violation']].agg('count').reset_index()

这里补充说明下去除columns的name及index的name的方法。

如下图所示"driver_race" 和 "driver_gender" 分别是columns的name,index的name。

下面演示一个平时较为头疼的事情。即将两个name删掉。下面介绍一个常见的方法。

使用pandas.DataFrame.rename_axis去除columns列的名称

代码语言:javascript
复制
# 第一步,重置索引
df_wide = df_pivot.reset_index()
# 重置name,设置为None即可
df_wide.rename_axis([None], axis=1)    
# columns有N个,就用N个None

另外一种情况如下图所示,在column上还有一个"driver_age",此时需要在第一步使用pandas.DataFrame.droplevel把"driver_age"删除:df.columns = df.columns.droplevel(0)

然后在执行上面两步。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据STUDIO 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数据基本情况
  • groupby数据透视表
    • 通过unstack重排数据表
    • pivot_table
    • 多级数据透视表
    • 自定义聚合函数
    • pandas.crosstab
    • 逆透视
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档