10.4 透视表和交叉表

    回到小费数据集,假设我想要根据day和smoker计算分组平均数(pivot_table的默认聚合类型),并将day和smoker放到行上:

    可以用groupby直接来做。现在,假设我们只想聚合tip_pct和size,而且想根据time进行分组。我将smoker放到列上,把day放到行上:

    1. .....: columns='smoker')
    2. Out[131]:
    3. size tip_pct
    4. smoker No Yes No Yes
    5. time day
    6. Dinner Fri 2.000000 2.222222 0.139622 0.165347
    7. Sat 2.555556 2.476190 0.158048 0.147906
    8. Sun 2.929825 2.578947 0.160113 0.187250
    9. Thur 2.000000 NaN 0.159744 NaN
    10. Lunch Fri 3.000000 1.833333 0.187735 0.188937
    11. Thur 2.500000 2.352941 0.160311 0.163863

    还可以对这个表作进一步的处理,传入margins=True添加分项小计。这将会添加标签为All的行和列,其值对应于单个等级中所有数据的分组统计:

    要使用其他的聚合函数,将其传给aggfunc即可。例如,使用count或len可以得到有关分组大小的交叉表(计数或频率):

    1. In [133]: tips.pivot_table('tip_pct', index=['time', 'smoker'], columns='day',
    2. .....: aggfunc=len, margins=True)
    3. time smoker
    4. Dinner No 3.0 45.0 57.0 1.0 106.0
    5. Yes 9.0 42.0 19.0 NaN 70.0
    6. Lunch No 1.0 NaN NaN 44.0 45.0
    7. Yes 6.0 NaN NaN 17.0 23.0
    8. All 19.0 87.0 76.0 62.0 244.0

    如果存在空的组合(也就是NA),你可能会希望设置一个fill_value:

    pivot_table的参数说明请参见表10-2。

    交叉表(cross-tabulation,简称crosstab)是一种用于计算分组频率的特殊透视表。看下面的例子:

    1. In [138]: data
    2. Out[138]:
    3. Sample Nationality Handedness
    4. 0 1 USA Right-handed
    5. 1 2 Japan Left-handed
    6. 2 3 USA Right-handed
    7. 3 4 Japan Right-handed
    8. 4 5 Japan Left-handed
    9. 6 7 USA Right-handed
    10. 7 8 USA Left-handed
    11. 8 9 Japan Right-handed
    12. 9 10 USA Right-handed

    作为调查分析的一部分,我们可能想要根据国籍和用手习惯对这段数据进行统计汇总。虽然可以用pivot_table实现该功能,但是pandas.crosstab函数会更方便:

    crosstab的前两个参数可以是数组或Series,或是数组列表。就像小费数据:

    1. In [140]: pd.crosstab([tips.time, tips.day], tips.smoker, margins=True)
    2. Out[140]:
    3. smoker No Yes All
    4. time day
    5. Dinner Fri 3 9 12
    6. Sat 45 42 87
    7. Sun 57 19 76
    8. Thur 1 0 1
    9. Lunch Fri 1 6 7
    10. Thur 44 17 61