如果你觉得内容对你有帮助,请在 GitHub 上点个 star 吧!

2.5. 分组汇总#

实际的数据分析中,经常需要对某一类数据进行统计分析。比如,假如我们拥有全国所有人的身高和体重数据,我们想按照省份分组,统计每个省的平均身高和平均体重,这时候就需要使用分组操作。pandas 提供了 groupby 函数进行类似的分组汇总操作。图 2.7 计算平均身高的分组汇总流程,主要包括两部分:分组与汇总。其中分组阶段将同一类的内容归结到相同的组中;汇总阶段将所关心的数据进行计算,比如求和、求平均等。

按哪些字段进行分组,这些字段又被成为 ** 分组变量 **。对其他字段进行汇总,其他汇总字段被成为 ** 汇总变量 **。对汇总变量进行计算,被称为 ** 汇总统计量 **。

../_images/groupby.svg

图 2.7 分组与汇总#

Hide code cell content
import os
import urllib.request
import zipfile
import pandas as pd

folder_path = os.path.join(os.getcwd(), "../data/pwt")
download_url = "https://www.rug.nl/ggdc/docs/pwt70_06032011version.zip"
file_name = download_url.split("/")[-1]
zip_file_path = os.path.join(folder_path, file_name)
if not os.path.exists(folder_path):
    os.makedirs(folder_path)

if not os.path.exists(zip_file_path):
    urllib.request.urlretrieve(download_url, zip_file_path)
    with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
        zip_ref.extractall(folder_path)

df = pd.read_csv(os.path.join(folder_path, "pwt70_w_country_names.csv"))
df = df.fillna(0)
文件夹已存在,无需操作。

分组变量#

在进行分组汇总时,分组变量可以有一个或多个。

例如,按照 countryyear 分组,并对 tcgdp 汇总求平均值,此时在 groupby 后接多个分组变量,以列表形式写出。或者是 .groupby(by=['country','year']).groupby 之后要接上所需要汇总的字段,这个例子是 tcgdp。最后要接上所需要进行的汇总计算,比如 .mean()。计算结果中产生了多个索引,本例中是 countryyear,指代相应组的情况。

df.groupby(['country','year'])[['tcgdp']].mean()
tcgdp
country year
Afghanistan 1950 0.000000
1951 0.000000
1952 0.000000
1953 0.000000
1954 0.000000
... ... ...
Zimbabwe 2005 1968.205961
2006 2132.305773
2007 2107.937100
2008 1772.209867
2009 1906.049843

11400 rows × 1 columns

汇总变量#

在进行分组汇总时,汇总变量也可以有一个或多个。

例如按照 year 汇总 tcgdpPOP,在 .groupby 后直接使用 [] 筛选相应列,再接汇总统计量。

df.groupby(['year'])[['tcgdp','POP']].mean()
tcgdp POP
year
1950 3954.394467 16239.392063
1951 4541.917011 16461.731179
1952 5150.946930 16730.487389
1953 5483.995310 17019.548668
1954 5692.811775 17326.304137
1955 6196.465477 17657.801874
1956 6640.264851 17999.434226
1957 7104.041128 18364.700442
1958 7528.454605 18730.439042
1959 8148.510891 19043.260395
1960 8828.605776 19242.437274
1961 9128.455879 19423.141142
1962 9687.307082 19760.533626
1963 10351.917775 20233.695226
1964 11269.680061 20719.860558
1965 12105.691273 21182.282832
1966 13176.722813 21655.463121
1967 14051.084235 22121.536947
1968 15421.584740 22606.150837
1969 17218.758987 23113.133937
1970 21282.567279 23618.829389
1971 23432.910689 24137.869711
1972 25833.379310 24644.483005
1973 29159.646600 25140.115900
1974 32601.678050 25623.884663
1975 36109.970163 26088.471411
1976 40165.947722 26535.470116
1977 44691.033777 26979.055474
1978 50393.152251 27418.046916
1979 56983.540963 27873.890479
1980 63850.748602 28329.849105
1981 70997.231877 28790.876000
1982 75786.116966 29287.531784
1983 81059.066064 29795.689879
1984 88303.031984 30288.007526
1985 94477.342887 30791.765868
1986 101596.414215 31313.561847
1987 109494.183517 31863.784021
1988 118048.078421 32417.290021
1989 126221.579493 32964.028537
1990 144220.075333 33516.168453
1991 151894.234358 34055.531837
1992 159301.705863 34567.649100
1993 168690.980704 35065.424347
1994 178947.613269 35548.469784
1995 190126.580304 36030.590795
1996 200132.766116 36513.694642
1997 210946.889843 36991.605037
1998 216481.948520 37462.231458
1999 228114.840291 37920.696968
2000 244206.601784 38307.409353
2001 255312.487062 38742.535742
2002 269661.409286 39176.028268
2003 286959.704885 39606.837547
2004 312186.334350 40040.118863
2005 344724.420195 40475.047642
2006 379205.674317 40909.750389
2007 416504.775669 41347.240695
2008 446441.988262 41731.031032
2009 448186.871127 42174.566563

汇总统计量#

groupby 后可接的汇总统计量有:

  • mean - 均值

  • max - 最大值

  • min - 最小值

  • median - 中位数

  • std - 标准差

  • mad - 平均绝对偏差

  • count - 计数

  • skew - 偏度

  • quantile - 指定分位数

这些统计量可以直接接 groupby 对象使用,此外,agg 方法提供了一次汇总多个统计量的方法。

例如,汇总各个国家 country 人口 POP 的均值、最大值、最小值。

df.groupby(['country'])['POP'].agg(['mean','min','max'])
mean min max
country
Afghanistan 15707.344917 8150.368 31889.923
Albania 2461.208000 1227.156 3250.778
Algeria 19896.967967 8892.718 34178.000
Angola 7295.199200 4117.617 12799.000
Antigua and Barbuda 65.352367 45.816 85.700
... ... ... ...
Venezuela 15180.664233 5009.006 27191.090
Vietnam 54711.902183 25348.144 88577.000
Yemen 10789.802917 4777.089 22858.000
Zambia 6448.586433 2553.000 13061.000
Zimbabwe 7567.034333 2853.151 11867.855

190 rows × 3 columns

多重索引#

在进行分组汇总操作时,产生的结果并不是常见的二维表数据框,而是具有多重索引的数据框。 pandas 开发者设计这种类型的数据框是借鉴了 Excel 数据透视表的功能。

例如,按照 countryyear 顺序对 tcgdpPOP 进行分组汇总,汇总统计量为最小值和最大值。

df.groupby(['country','year'])[['tcgdp','POP']].agg(['min','max'])
tcgdp POP
min max min max
country year
Afghanistan 1950 0.000000 0.000000 8150.368 8150.368
1951 0.000000 0.000000 8284.473 8284.473
1952 0.000000 0.000000 8425.333 8425.333
1953 0.000000 0.000000 8573.217 8573.217
1954 0.000000 0.000000 8728.408 8728.408
... ... ... ... ... ...
Zimbabwe 2005 1968.205961 1968.205961 11639.470 11639.470
2006 2132.305773 2132.305773 11544.326 11544.326
2007 2107.937100 2107.937100 11443.187 11443.187
2008 1772.209867 1772.209867 11350.000 11350.000
2009 1906.049843 1906.049843 11383.000 11383.000

11400 rows × 4 columns

此时数据框中有两个行索引(countryyear)和两个列索引(tcgdp + POPmin + max)。需要筛选列时,第一个 [] 筛选第一重列索引(从 tcgdpPOP 中选择一个列),第二个 [] 筛选第二重列索引(从 minmax 中选择一个列)。

例如,查询各个国家 country 各年 year 人口 POP 的最小值。

df_query = df.groupby(['country','year'])[['tcgdp','POP']].agg(['min','max'])
df_query['POP']['min']
country      year
Afghanistan  1950     8150.368
             1951     8284.473
             1952     8425.333
             1953     8573.217
             1954     8728.408
                       ...    
Zimbabwe     2005    11639.470
             2006    11544.326
             2007    11443.187
             2008    11350.000
             2009    11383.000
Name: min, Length: 11400, dtype: float64