查看全课大纲(第 56 / 101 节)
  1. 1.数据分析基本概念
  2. 2.学习数据分析的一般路线
  3. 3.数据分析的流程
  4. 4.数据类型
  5. 5.环境部署(1)
  6. 6.环境部署(2)
  7. 7.课程介绍
  8. 8.TXT文件操作
  9. 9.JSON文件操作
  10. 10.CSV文件操作
  11. 11.Excel文件操作
  12. 12.数据库及SQL常用语法
  13. 13.数据库基本操作
  14. 14.数据库多表连接
  15. 15.实战:欧洲职业足球数据库分析
  16. 16.爬虫简介
  17. 17.URL管理模块
  18. 18.网页下载模块
  19. 19.网页解析模块(1)
  20. 20.网页解析模块(2)
  21. 21.Scrapy简介
  22. 22.Scrapy使用步骤(1)
  23. 23.Scrapy使用步骤(2)
  24. 24.Scrapy使用步骤(3)
  25. 25.Scrapy使用步骤(4)
  26. 26.实战:获取国内城市空气质量指数数据
  27. 27.NumPy和SciPy介绍
  28. 28.多维数组
  29. 29.多维数组操作
  30. 30.NumPy的常用方法
  31. 31.向量化介绍
  32. 32.向量化及通用函数
  33. 33.实战:2016美国大选分析
  34. 34.数据结构-Series
  35. 35.数据结构-DataFrame
  36. 36.数据结构-Index
  37. 37.Series的索引操作
  38. 38.DataFrame的索引操作
  39. 39.索引操作总结
  40. 40.运算与对齐
  41. 41.函数应用操作(1) -- map
  42. 42.函数应用操作 (2) -- apply applymap
  43. 43.文件读写操作
  44. 44.排序操作
  45. 45.数据清洗--处理缺失数据
  46. 46.数据清洗--处理重复数据
  47. 47.数据清洗--替换数据
  48. 48.常用统计方法(1) -- describe quantile
  49. 49.常用统计方法(2) -- sum mean median count
  50. 50.常用统计方法(3) -- max min idxmax idxmin
  51. 51.常用统计方法(4) -- mad var std cumsum
  52. 52.实战:全球食品数据分析
  53. 53.层级索引
  54. 54.分组与聚合介绍
  55. 55.分组操作(1) -- GroupBy对象及常用聚合操作
  56. 56.分组操作(2) -- 自定义分组及聚合操作
  57. 57.透视表介绍
  58. 58.透视表操作
  59. 59.数据规整(1) -- 数据合并concat
  60. 60.数据规整(2) -- 数据连接merge
  61. 61.数据重构(3) -- 数据重构stack unstack
  62. 62.实战:互联网电影资料库分析
  63. 63.探索性数据分析EDA介绍
  64. 64.EDA的目的
  65. 65.EDA常用工具
  66. 66.Matplotlib绘图基本介绍
  67. 67.Matplotlib画布
  68. 68.散点图和柱状图的绘制
  69. 69.直方图的绘制
  70. 70.矩阵绘图
  71. 71.子图的使用
  72. 72.Matplotlib颜色、标记、线型
  73. 73.Matplotlib坐标刻度、标签、图例、标题
  74. 74.Seaborn介绍
  75. 75.数据集分布可视化(1) -- 单变量分布、双变量分布
  76. 76.数据集分布可视化(2) -- 变量关系可视化
  77. 77.类别数据可视化 -- 类别散布图、类别内数据分布、类别内统计图
  78. 78.交互式数据可视化工具Bokeh介绍
  79. 79.Bokeh绘制散点图、柱状图、盒子图、弦图
  80. 80.Bokeh绘制常用图形元素
  81. 81.3D绘图 -- mplot3d
  82. 82.3D曲线可视化
  83. 83.3D散点图可视化
  84. 84.3D柱状图可视化
  85. 85.Pandas绘图
  86. 86.实战:Lending Club借贷数据探索性分析及可视化
  87. 87.机器学习介绍及应用场景
  88. 88.机器学习建模介绍 (1) -- 分类
  89. 89.机器学习建模介绍 (2) -- 回归
  90. 90.机器学习建模介绍 (3) -- 聚类
  91. 91.机器学习分类
  92. 92.机器学习工具scikit-learn
  93. 93.使用scikit-learn的流程
  94. 94.数据集准备及划分
  95. 95.模型选择
  96. 96.数据预处理及特征工程
  97. 97.过拟合与欠拟合
  98. 98.模型调参介绍
  99. 99.模型调参方法
  100. 100.模型测试及评价
  101. 101.实战:通过移动设备行为数据预测性别和年龄

分组操作(2) -- 自定义分组及聚合操作

约 12 分钟

📺 正在播放小象学院官方高清录播(支持倍速与清晰度调节)

分组操作(2)——自定义分组及聚合操作

小象实战讲义 · Python数据分析实战

在上一节中,我们掌握了Pandas分组操作的基本方法。然而,现实数据分析中,我们常常需要根据更复杂的规则对数据进行分组,或者执行非标准的聚合计算。本节将带你深入分组操作的高级应用,学习如何通过自定义规则进行分组,以及如何使用agg()函数实现灵活多样的聚合操作,从而应对更复杂的分析需求。

💡 核心导读

  • 自定义分组:学习两种实现自定义分组的方法,包括直接向groupby()传入函数,以及先构造分组列再分组。
  • agg()函数详解:掌握agg()函数的核心用法,它是实现灵活聚合操作的“瑞士军刀”。
  • 多聚合与列定制:了解如何一次性对分组数据执行多个聚合操作,并为不同列指定不同的聚合函数。
  • 自定义聚合函数:学习如何编写并使用自定义函数进行聚合,以获取更深层次的数据洞察。

自定义分组

在标准的分组操作中,我们通常按某一列或多列的唯一值进行分组。但有时,我们需要根据更复杂的业务逻辑或自定义规则来划分数据组。例如,将连续数值(如幸福指数)划分为“高”、“中”、“低”三档,然后按档位进行分析。Pandas提供了两种主要方法来实现自定义分组。

方法一:向groupby()传入自定义函数

这种方法的核心是:groupby()可以接受一个函数作为分组依据。该函数会应用于索引(index)的每个元素,并根据函数的返回值进行分组。

让我们通过一个具体的例子来理解。假设我们有一份关于国家幸福指数的数据,我们希望根据“幸福指数”(Happiness Score)的高低进行自定义分组。

首先,我们构造一份简化的示例数据,并定义分组规则。

import pandas as pd
import numpy as np

# 构造示例数据:国家、区域、幸福排名、幸福指数
data = pd.DataFrame({
    'Country': ['Finland', 'Denmark', 'Switzerland', 'Iceland', 'Norway', 'Netherlands', 'Canada', 'New Zealand', 'Sweden', 'Australia'],
    'Region': ['Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'North America', 'Oceania', 'Western Europe', 'Oceania'],
    'Happiness Rank': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'Happiness Score': [7.769, 7.600, 7.554, 7.494, 7.488, 7.284, 7.278, 7.267, 7.231, 7.223]
})

# 自定义分组规则函数
def get_score_group(score):
    """根据幸福指数返回分组标签"""
    if score <= 7.2:
        score_group = 'low'
    elif score <= 7.5:
        score_group = 'middle'
    else:
        score_group = 'high'
    return score_group

# 方法1:将'Happiness Score'设为索引,然后按自定义函数分组
data_score_as_index = data.set_index('Happiness Score')
group_sizes = data_score_as_index.groupby(get_score_group).size()

print("按自定义函数分组结果(方法1):")
print(group_sizes)
按自定义函数分组结果(方法1):
Happiness Score
high      3
middle    7
dtype: int64

关键点解析:

  1. 操作对象是索引:自定义函数get_score_group被应用于data_score_as_index的索引(即Happiness Score列的值)。
  2. 分组依据是函数返回值:函数返回'low'、'middle'或'high',数据将根据这三个返回值被分为三组。
  3. 结果:从输出可见,我们的示例数据中,幸福指数“高”(high,得分 > 7.5)的国家有3个,“中”(middle,7.2 < 得分 ≤ 7.5)的国家有7个,没有“低”(low,得分 ≤ 7.2)分组。

方法二:先构造分组列,再分组

这是项目实践中更常用、更直观的方法。思路是:先利用apply()等方法,在DataFrame中新增一列,该列的值就是我们的自定义分组标签,然后再对这一新列进行常规的groupby操作。

import pandas as pd
import numpy as np

# 构造示例数据
data = pd.DataFrame({
    'Country': ['Finland', 'Denmark', 'Switzerland', 'Iceland', 'Norway', 'Netherlands', 'Canada', 'New Zealand', 'Sweden', 'Australia'],
    'Region': ['Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'North America', 'Oceania', 'Western Europe', 'Oceania'],
    'Happiness Rank': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'Happiness Score': [7.769, 7.600, 7.554, 7.494, 7.488, 7.284, 7.278, 7.267, 7.231, 7.223]
})

# 自定义分组规则函数
def get_score_group(score):
    """根据幸福指数返回分组标签"""
    if score <= 7.2:
        score_group = 'low'
    elif score <= 7.5:
        score_group = 'middle'
    else:
        score_group = 'high'
    return score_group

# 方法2:先创建分组列,再按该列分组
data['score_group'] = data['Happiness Score'].apply(get_score_group)

print("添加分组列后的数据(最后5行):")
print(data.tail())
print("\n按分组列分组结果(方法2):")
print(data.groupby('score_group').size())
添加分组列后的数据(最后5行):
       Country          Region  Happiness Rank  Happiness Score score_group
5  Netherlands  Western Europe               6            7.284      middle
6       Canada   North America               7            7.278      middle
7  New Zealand         Oceania               8            7.267      middle
8       Sweden  Western Europe               9            7.231      middle
9    Australia         Oceania              10            7.223      middle

按分组列分组结果(方法2):
score_group
high      3
middle    7
dtype: int64

方法对比与选择:

  • 方法一更简洁,但要求分组依据的列必须是索引,理解上稍绕。
  • 方法二步骤清晰,新增的列直观可见,便于后续检查和复用,是工程实践中的首选。

自定义聚合操作

在基础分组中,我们使用.max()、.min()、.mean()等方法进行聚合。实际上,这些方法都是agg()函数的快捷方式。agg()(aggregation的缩写)是Pandas中功能更强大、更灵活的聚合接口。

认识agg()函数

agg()函数可以接受多种形式的参数:单个函数、函数列表、字典等,从而实现从简单到复杂的聚合需求。

1. 基础聚合与agg()等价形式

import pandas as pd
import numpy as np

# 构造示例数据
data = pd.DataFrame({
    'Country': ['Finland', 'Denmark', 'Switzerland', 'Iceland', 'Norway', 'Netherlands', 'Canada', 'New Zealand', 'Sweden', 'Australia'],
    'Region': ['Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'North America', 'Oceania', 'Western Europe', 'Oceania'],
    'Happiness Rank': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'Happiness Score': [7.769, 7.600, 7.554, 7.494, 7.488, 7.284, 7.278, 7.267, 7.231, 7.223]
})

# 等价操作:按区域分组,求最大值
max_by_region_direct = data.groupby('Region').max()
max_by_region_agg = data.groupby('Region').agg(np.max)

print("直接使用.max()方法:")
print(max_by_region_direct[['Happiness Rank', 'Happiness Score']])
print("\n使用agg(np.max)方法:")
print(max_by_region_agg[['Happiness Rank', 'Happiness Score']])
直接使用.max()方法:
                Happiness Rank  Happiness Score
Region
North America                7            7.278
Oceania                     10            7.267
Western Europe               9            7.769

使用agg(np.max)方法:
                Happiness Rank  Happiness Score
Region
North America                7            7.278
Oceania                     10            7.267
Western Europe               9            7.769

两种方式结果完全一致,agg()提供了更明确的聚合意图表达。

2. 传入函数列表:一次性完成多聚合

agg()的强大之处在于可以一次性对同一列执行多个聚合计算。

import pandas as pd
import numpy as np

# 构造示例数据
data = pd.DataFrame({
    'Country': ['Finland', 'Denmark', 'Switzerland', 'Iceland', 'Norway', 'Netherlands', 'Canada', 'New Zealand', 'Sweden', 'Australia'],
    'Region': ['Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'North America', 'Oceania', 'Western Europe', 'Oceania'],
    'Happiness Rank': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'Happiness Score': [7.769, 7.600, 7.554, 7.494, 7.488, 7.284, 7.278, 7.267, 7.231, 7.223]
})

# 使用agg()函数,传入函数列表进行多聚合操作
multi_agg = data.groupby('Region')['Happiness Score'].agg([np.max, np.min, np.mean])

print("按区域分组的多聚合统计(最大值、最小值、均值):")
print(multi_agg)
按区域分组的多聚合统计(最大值、最小值、均值):
                  max    min      mean
Region
North America   7.278  7.278  7.278000
Oceania         7.267  7.223  7.245000
Western Europe  7.769  7.231  7.488571

输出结果中的 max、min、mean 列,分别是 np.max、np.min、np.mean 聚合函数计算出的结果。(补充版本口径:旧版 pandas 会用 amax/amin 这样的函数名作列名,新版已按 max/min 输出——以你环境实际打印为准。)

3. 传入字典:为不同列指定不同聚合函数

当DataFrame有多列时,我们可能希望对不同列应用不同的聚合操作。这时,可以向agg()传入一个字典,其中键为列名,值为该列要应用的聚合函数。

import pandas as pd
import numpy as np

# 构造示例数据
data = pd.DataFrame({
    'Country': ['Finland', 'Denmark', 'Switzerland', 'Iceland', 'Norway', 'Netherlands', 'Canada', 'New Zealand', 'Sweden', 'Australia'],
    'Region': ['Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'North America', 'Oceania', 'Western Europe', 'Oceania'],
    'Happiness Rank': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'Happiness Score': [7.769, 7.600, 7.554, 7.494, 7.488, 7.284, 7.278, 7.267, 7.231, 7.223]
})

# 使用字典为不同列指定不同的聚合函数
dict_agg = data.groupby('Region').agg({
    'Happiness Score': np.mean,  # 幸福指数求均值
    'Happiness Rank': np.max     # 排名求最大值(即最差排名)
})

print("按区域分组,不同列使用不同聚合函数:")
print(dict_agg)
按区域分组,不同列使用不同聚合函数:
                Happiness Score  Happiness Rank
Region
North America          7.278000               7
Oceania                7.245000              10
Western Europe         7.488571               9

4. 传入自定义聚合函数

最灵活的方式是传入自定义函数。这允许我们实现任何复杂的、非标准的聚合逻辑。

例如,我们想分析每个区域内幸福排名的“两极分化”程度,可以计算每个组内排名最大值与最小值的差值(极差)。

import pandas as pd
import numpy as np

# 构造示例数据
data = pd.DataFrame({
    'Country': ['Finland', 'Denmark', 'Switzerland', 'Iceland', 'Norway', 'Netherlands', 'Canada', 'New Zealand', 'Sweden', 'Australia'],
    'Region': ['Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'Western Europe', 'North America', 'Oceania', 'Western Europe', 'Oceania'],
    'Happiness Rank': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'Happiness Score': [7.769, 7.600, 7.554, 7.494, 7.488, 7.284, 7.278, 7.267, 7.231, 7.223]
})

# 自定义聚合函数:计算最大值与最小值的差值(极差)
def max_min_diff(x):
    """计算序列中最大值与最小值的差值"""
    return x.max() - x.min()

# 应用自定义聚合函数:计算每个区域幸福排名的极差
rank_diff_by_region = data.groupby('Region')['Happiness Rank'].agg(max_min_diff)

print("按区域分组,幸福排名的极差(最大值-最小值):")
print(rank_diff_by_region)
按区域分组,幸福排名的极差(最大值-最小值):
Region
North America     0
Oceania           2
Western Europe    8
Name: Happiness Rank, dtype: int64

结果解读:Western Europe地区幸福排名的极差为8(从第1名到第9名),说明该区域内国家的幸福水平分布范围较广。而North America地区(本例中只有加拿大)极差为0,Oceania地区极差为2,分布相对集中。

📝 动手练一练

  1. 概念辨析:在“自定义分组”的两种方法中,方法一要求分组依据的列必须是索引,而方法二则是在数据中新增一列。请简述在什么场景下你会优先选择方法二?为什么?
👉 点击查看参考答案

在大多数项目实践场景中,我会优先选择方法二(先构造分组列)。原因如下:

  • 直观清晰:新增的列直接呈现在DataFrame中,分组依据一目了然,便于代码审查和数据验证。
  • 便于复用:构造好的分组列可以保存下来,供后续不同的分析步骤使用,避免重复计算。
  • 灵活性高:不依赖于索引的设置,对数据的原始结构改动小,更符合“数据管道”的处理思想。
  • 易于调试:如果分组规则复杂,可以先单独测试apply函数在新列上的结果是否正确,再执行分组,降低了调试难度。
  1. 动手实践:假设我们想分析“幸福指数的稳定性”,定义一个自定义聚合函数,计算每个区域幸福指数的变异系数(标准差/均值)。请基于下面的示例数据,编写代码实现这一分析。
import pandas as pd
import numpy as np

# 示例数据
data = pd.DataFrame({
    'Region': ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C'],
    'Happiness Score': [7.8, 7.9, 7.7, 6.5, 6.6, 6.4, 5.0, 9.0]
})
# 请在此处补充你的代码
👉 点击查看参考答案
import pandas as pd
import numpy as np

# 示例数据
data = pd.DataFrame({
    'Region': ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C'],
    'Happiness Score': [7.8, 7.9, 7.7, 6.5, 6.6, 6.4, 5.0, 9.0]
})

# 自定义聚合函数:计算变异系数
def coefficient_of_variation(x):
    """计算变异系数:标准差/均值"""
    # 注意:为避免除零错误,实际应用中需考虑均值接近0的情况
    return x.std() / x.mean()

# 应用自定义函数
cv_result = data.groupby('Region')['Happiness Score'].agg(coefficient_of_variation)

print("各区域幸福指数变异系数:")
print(cv_result)
各区域幸福指数变异系数:
Region
A    0.012821
B    0.015385
C    0.404061
Name: Happiness Score, dtype: float64

结果解读:区域C的变异系数远高于A和B,说明区域C内国家的幸福指数波动非常大(从5.0到9.0),稳定性最差。区域A的变异系数最小,幸福指数最稳定。

本章小结

本节我们深入探讨了Pandas分组操作中更高级、更灵活的部分——自定义分组与自定义聚合。掌握这些技能,能让你在面对复杂多变的业务分析需求时游刃有余。

📋 行动清单

  • 练习自定义分组:找一份包含数值型评分的数据,尝试编写函数将其分为“优、良、中、差”等级,并用两种方法实现分组统计。
  • 掌握agg()的多种用法:对一个分组对象,分别使用单个函数、函数列表和字典参数调用agg(),观察输出结果的异同。
  • 设计一个自定义聚合指标:结合你的业务领域(如电商、金融、社交),思考一个非标准的聚合需求(如“连续上涨天数”、“用户活跃度得分”),并尝试用自定义函数在分组中实现它。

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 本节课件:分组操作(2) -- 自定义分组及聚合操作
    PDF · 164KB
    下载
  • 全套课件打包(第1-5章)
    ZIP · 12.8MB
    下载
  • 全套课件打包(第6-8章)
    ZIP · 15MB
    下载
  • 实战数据集:AppleStore 应用商城分析
    ZIP · 329KB
    下载
  • 实战数据集:女性服装电商分析
    ZIP · 2.8MB
    下载
  • Python 数据分析环境搭建指南
    PDF · 2MB
    下载
  • Scrapy 安装教程
    PDF · 12.7MB
    下载
  • 附加实战项目:AppleStore 应用商城数据分析
    ZIP · 0.3MB · ipynb + CSV 数据
    下载
  • 附加实战项目:银行电话营销数据分析
    ZIP · 0.4MB · ipynb + CSV 数据
    下载
  • 附加实战项目:女性服装电商评论数据分析
    ZIP · 2.7MB · ipynb + CSV 数据
    下载
  • 附加实战项目:美国化学学会杂志数据分析
    ZIP · 34.2MB · ipynb + SQLite 数据库
    下载