2.5. 分组汇总#
实际的数据分析中,经常需要对某一类数据进行统计分析。比如,假如我们拥有全国所有人的身高和体重数据,我们想按照省份分组,统计每个省的平均身高和平均体重,这时候就需要使用分组操作。pandas 提供了 groupby 函数进行类似的分组汇总操作。图 2.7 计算平均身高的分组汇总流程,主要包括两部分:分组与汇总。其中分组阶段将同一类的内容归结到相同的组中;汇总阶段将所关心的数据进行计算,比如求和、求平均等。
按哪些字段进行分组,这些字段又被成为 ** 分组变量 **。对其他字段进行汇总,其他汇总字段被成为 ** 汇总变量 **。对汇总变量进行计算,被称为 ** 汇总统计量 **。
图 2.7 分组与汇总#
Show 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)
文件夹已存在,无需操作。
分组变量#
在进行分组汇总时,分组变量可以有一个或多个。
例如,按照 country 和 year 分组,并对 tcgdp 汇总求平均值,此时在 groupby 后接多个分组变量,以列表形式写出。或者是 .groupby(by=['country','year'])。.groupby 之后要接上所需要汇总的字段,这个例子是 tcgdp。最后要接上所需要进行的汇总计算,比如 .mean()。计算结果中产生了多个索引,本例中是 country 和 year,指代相应组的情况。
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 汇总 tcgdp 和 POP,在 .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 数据透视表的功能。
例如,按照 country 和 year 顺序对 tcgdp 和 POP 进行分组汇总,汇总统计量为最小值和最大值。
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
此时数据框中有两个行索引(country 和 year)和两个列索引(tcgdp + POP 和 min + max)。需要筛选列时,第一个 [] 筛选第一重列索引(从 tcgdp 和 POP 中选择一个列),第二个 [] 筛选第二重列索引(从 min 和 max 中选择一个列)。
例如,查询各个国家 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