• pandas教程:Pivot Tables and Cross-Tabulation 数据透视表和交叉表


    10.4 Pivot Tables and Cross-Tabulation(数据透视表和交叉表)

    Pivot Tables(数据透视表)是一种常见的数据汇总工具,常见与各种spreadsheet programs(电子表格程序,比如Excel)和一些数据分析软件。它能按一个或多个keys来把数据聚合为表格,能沿着行或列,根据组键来整理数据。

    数据透视表可以用pandasgroupby来制作,这个本节会进行介绍,除此之外还会有介绍如何利用多层级索引来进行reshape(更改形状)操作。DataFrame有一个pivot_table方法,另外还有一个pandas.pivot_table函数。为了有一个更方便的groupby接口,pivot_table能添加partial totals(部分合计),也被称作margins(边界)。

    回到之前提到的tipping数据集,假设我们想要计算一个含有组平均值的表格(a table of group means,这个平均值也是pivot_table默认的聚合类型),按daysmoker来分组:

    import numpy as np
    import pandas as pd
    
    • 1
    • 2
    tips = pd.read_csv('../examples/tips.csv')
    # Add tip percentage of total bill
    tips['tip_pct'] = tips['tip'] / tips['total_bill']
    
    • 1
    • 2
    • 3
    tips.head()
    
    • 1
    total_billtipsmokerdaytimesizetip_pct
    016.991.01NoSunDinner20.059447
    110.341.66NoSunDinner30.160542
    221.013.50NoSunDinner30.166587
    323.683.31NoSunDinner20.139780
    424.593.61NoSunDinner40.146808
    tips.pivot_table(index=['day', 'smoker'])
    
    • 1
    sizetiptip_pcttotal_bill
    daysmoker
    FriNo2.2500002.8125000.15165018.420000
    Yes2.0666672.7140000.17478316.813333
    SatNo2.5555563.1028890.15804819.661778
    Yes2.4761902.8754760.14790621.276667
    SunNo2.9298253.1678950.16011320.506667
    Yes2.5789473.5168420.18725024.120000
    ThurNo2.4888892.6737780.16029817.113111
    Yes2.3529413.0300000.16386319.190588

    这个结果也可以通过groupby直接得到。

    现在假设我们想要按time分组,然后对tip_pctsize进行聚合。我们会把smoker放在列上,而day用于行:

    tips.pivot_table(['tip_pct', 'size'], index=['time', 'day'],
                     columns='smoker')
    
    • 1
    • 2
    tip_pctsize
    smokerNoYesNoYes
    timeday
    DinnerFri0.1396220.1653472.0000002.222222
    Sat0.1580480.1479062.5555562.476190
    Sun0.1601130.1872502.9298252.578947
    Thur0.159744NaN2.000000NaN
    LunchFri0.1877350.1889373.0000001.833333
    Thur0.1603110.1638632.5000002.352941

    我们也快成把这个表格加强一下,通过设置margins=True来添加部分合计(partial total)。这么做的话有一个效果,会给行和列各添加All标签,这个All表示的是当前组对于整个数据的统计值:

    tips.pivot_table(['tip_pct', 'size'], index=['time', 'day'],
                     columns='smoker', margins=True)
    
    • 1
    • 2
    tip_pctsize
    smokerNoYesAllNoYesAll
    timeday
    DinnerFri0.1396220.1653470.1589162.0000002.2222222.166667
    Sat0.1580480.1479060.1531522.5555562.4761902.517241
    Sun0.1601130.1872500.1668972.9298252.5789472.842105
    Thur0.159744NaN0.1597442.000000NaN2.000000
    LunchFri0.1877350.1889370.1887653.0000001.8333332.000000
    Thur0.1603110.1638630.1613012.5000002.3529412.459016
    All0.1593280.1631960.1608032.6688742.4086022.569672

    这里,对于All列,这一列的值是不考虑吸烟周和非吸烟者的平均值(smoker versus nonsmoker)。对于All行,这一行的值是不考虑任何组中任意两个组的平均值(any of the two levels of grouping)。

    想要使用不同的聚合函数,传递给aggfunc即可。例如,countlen可以给我们一个关于组大小(group size)的交叉表格:

    tips.pivot_table('tip_pct', index=['time', 'smoker'], columns='day',
                     aggfunc=len, margins=True)
    
    • 1
    • 2
    dayFriSatSunThurAll
    timesmoker
    DinnerNo3.045.057.01.0106.0
    Yes9.042.019.0NaN70.0
    LunchNo1.0NaNNaN44.045.0
    Yes6.0NaNNaN17.023.0
    All19.087.076.062.0244.0

    如果一些组合是空的(或NA),我们希望直接用fill_value来填充:

    tips.pivot_table('tip_pct', index=['time', 'size', 'smoker'],
                     columns='day', aggfunc='mean', fill_value=0)
    
    • 1
    • 2
    dayFriSatSunThur
    timesizesmoker
    Dinner1No0.0000000.1379310.0000000.000000
    Yes0.0000000.3257330.0000000.000000
    2No0.1396220.1627050.1688590.159744
    Yes0.1712970.1486680.2078930.000000
    3No0.0000000.1546610.1526630.000000
    Yes0.0000000.1449950.1526600.000000
    4No0.0000000.1500960.1481430.000000
    Yes0.1177500.1245150.1933700.000000
    5No0.0000000.0000000.2069280.000000
    Yes0.0000000.1065720.0656600.000000
    6No0.0000000.0000000.1037990.000000
    Lunch1No0.0000000.0000000.0000000.181728
    Yes0.2237760.0000000.0000000.000000
    2No0.0000000.0000000.0000000.166005
    Yes0.1819690.0000000.0000000.158843
    3No0.1877350.0000000.0000000.084246
    Yes0.0000000.0000000.0000000.204952
    4No0.0000000.0000000.0000000.138919
    Yes0.0000000.0000000.0000000.155410
    5No0.0000000.0000000.0000000.121389
    6No0.0000000.0000000.0000000.173706

    1 Cross-Tabulations: Crosstab(交叉表:Crosstab)

    cross-tabulation(交叉表,简写为crosstab),是数据透视表的一个特殊形式,只计算组频率(group frequencies)。这里有个例子:

    data = pd.DataFrame({'Sample': np.arange(1, 11),
            'Nationality': ['USA', 'Japan', 'USA', 'Japan', 'Japan', 'Japan', 'USA', 'USA', 'Japan', 'USA'],
            'Handedness': ['Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed']})
    data
    
    • 1
    • 2
    • 3
    • 4
    HandednessNationalitySample
    0Right-handedUSA1
    1Left-handedJapan2
    2Right-handedUSA3
    3Right-handedJapan4
    4Left-handedJapan5
    5Right-handedJapan6
    6Right-handedUSA7
    7Left-handedUSA8
    8Right-handedJapan9
    9Right-handedUSA10

    作为调查分析(survey analysis)的一部分,我们想要按国家和惯用手来进行汇总。我们可以使用pivot_table来做到这点,不过pandas.crosstab函数会更方便一些:

    pd.crosstab(data.Nationality, data.Handedness, margins=True)
    
    • 1
    HandednessLeft-handedRight-handedAll
    Nationality
    Japan235
    USA145
    All3710

    crosstab的前两个参数可以是数组或Series或由数组组成的列表(a list of array)。对于tips数据,可以这么写:

    pd.crosstab([tips.time, tips.day], tips.smoker, margins=True)
    
    • 1
    smokerNoYesAll
    timeday
    DinnerFri3912
    Sat454287
    Sun571976
    Thur101
    LunchFri167
    Thur441761
    All15193244
  • 相关阅读:
    《前端开发实战 · videojs 视频需求开发》
    机器人工具箱学习(三)
    【计算机网络:自顶向下方法】(二)应用层
    链路状态路由协议OSPF的LSA头部讲解
    EasyWeChat6.x生成小程序码, JSON 数据时遇到了非法的 UTF-8 字符序列
    IDEA插件开发(22)--Status Bar Widgets
    解压apk后各文件夹含义
    【OpenCV 例程200篇】216. 绘制多段线和多边形
    短视频脚本如何创作?了解构成部分很关键,按顺序做不会错
    个人开发笔记
  • 原文地址:https://blog.csdn.net/weixin_46530492/article/details/134487335