Pandas系列(九)-分组聚合详解
目录
- 1. 将对象分割成组
- 1.1 关闭排序
- 1.2 选择列
- 1.3 遍历分组
- 1.4 选择一个组
- 2. 聚合
- 2.1 一次应用多个聚合操作
- 2.2 对DataFrame列应用不同的聚合操作
- 3. transform 操作
- 4. apply 操作
数据准备
# 导入相关库
import numpy as np
import pandas as pd
index = pd.Index(data=["Tom", "Bob", "Mary", "James", "Andy", "Alice"], name="name")
data = {
"age": [18, 30, 35, 18, np.nan, 30],
"city": ["Bei Jing ", "Shang Hai ", "Guang Zhou", "Shen Zhen", np.nan, " "],
"sex": ["male", "male", "female", "male", np.nan, "female"],
"income": [3000, 8000, 8000, 4000, 6000, 7000]
}
user_info = pd.DataFrame(data=data, index=index)
user_info
Out[59]:
age city sex income
name
Tom 18.0 Bei Jing male 3000
Bob 30.0 Shang Hai male 8000
Mary 35.0 Guang Zhou female 8000
James 18.0 Shen Zhen male 4000
Andy NaN NaN NaN 6000
Alice 30.0 female 7000
1.将对象分割成组
在进行分组统计前,首先要做的就是进行分组。既然是分组,就需要依赖于某个信息。比如,依据性别来分组。直接调用 user_info.groupby(user_info["sex"])即可完成按照性别分组。
grouped = user_info.groupby(user_info["sex"])
grouped.groups
Out[60]:
{'female': Index(['Mary', 'Alice'], dtype='object', name='name'),
'male': Index(['Tom', 'Bob', 'James'], dtype='object', name='name')}
#可以看到,已经能够正确的按照性别来进行分组了。通常我们为了更简单,会使用这种方式来实现相同的功能:user_info.groupby("sex")
grouped = user_info.groupby('sex')
grouped.groups
Out[61]:
{'female': Index(['Mary', 'Alice'], dtype='object', name='name'),
'male': Index(['Tom', 'Bob', 'James'], dtype='object', name='name')}
#先按性别分组,后按年龄分组
grouped = user_info.groupby(["sex", "age"])
grouped.groups
Out[62]:
{('male', 18.0): Index(['Tom', 'James'], dtype='object', name='name'),
('male', 30.0): Index(['Bob'], dtype='object', name='name'),
('female', 35.0): Index(['Mary'], dtype='object', name='name'),
(nan, nan): Index(['Andy'], dtype='object', name='name'),
('female', 30.0): Index(['Alice'], dtype='object', name='name')}
1.1关闭排序
默认情况下,groupby 会在操作过程中对数据进行排序。如果为了更好的性能,可以设置 sort=False。
grouped = user_info.groupby(["sex", "age"], sort=False)
grouped.groups
Out[63]:
{('male', 18.0): Index(['Tom', 'James'], dtype='object', name='name'),
('male', 30.0): Index(['Bob'], dtype='object', name='name'),
('female', 35.0): Index(['Mary'], dtype='object', name='name'),
(nan, nan): Index(['Andy'], dtype='object', name='name'),
('female', 30.0): Index(['Alice'], dtype='object', name='name')}
1.2 选择列
在使用 groupby 进行分组后,可以使用切片 [] 操作来完成对某一列的选择。
grouped = user_info.groupby("sex")
grouped.city #grouped['city']
Out[64]: <pandas.core.groupby.groupby.SeriesGroupBy object at 0x000000BDFE7DA550>
1.3 遍历分组
在对数据进行分组后,可以进行遍历。如果是根据多个字段来分组的,每个组的名称是一个元组。
grouped = user_info.groupby("sex")
for name, group in grouped:
print("name: {}".format(name))
print("group: {}".format(group))
print("--------------") name: female
group: age city sex income
name
Mary 35.0 Guang Zhou female 8000
Alice 30.0 female 7000
--------------
name: male
group: age city sex income
name
Tom 18.0 Bei Jing male 3000
Bob 30.0 Shang Hai male 8000
James 18.0 Shen Zhen male 4000
--------------
按性别和年龄分组
grouped = user_info.groupby(["sex", "age"])
for name, group in grouped:
print("name: {}".format(name))
print("group: {}".format(group))
print("--------------") name: ('female', 30.0)
group: age city sex income
name
Alice 30.0 female 7000
--------------
name: ('female', 35.0)
group: age city sex income
name
Mary 35.0 Guang Zhou female 8000
--------------
name: ('male', 18.0)
group: age city sex income
name
Tom 18.0 Bei Jing male 3000
James 18.0 Shen Zhen male 4000
--------------
name: ('male', 30.0)
group: age city sex income
name
Bob 30.0 Shang Hai male 8000
--------------
1.4 选择一个组
分组后,我们可以通过 get_group 方法来选择其中的某一个组。
grouped = user_info.groupby("sex")
grouped.get_group("male")
user_info.groupby(["sex", "age"]).get_group(("male", 18))
Out[67]:
age city sex income
name
Tom 18.0 Bei Jing male 3000
James 18.0 Shen Zhen male 4000
2. 聚合
分组的目的是为了统计,统计的时候需要聚合,所以我们需要在分完组后来看下如何进行聚合。常见的一些聚合操作有:计数、求和、最大值、最小值、平均值等。想要实现聚合操作,一种方式就是调用 agg 方法。
# 获取不同性别下所包含的人数
grouped = user_info.groupby("sex")
grouped["age"].agg(len)
Out[68]:
sex
female 2.0
male 3.0
Name: age, dtype: float64
#grouped.age.count()
#grouped.age.size()
# 获取不同性别下包含的最大的年龄
grouped = user_info.groupby("sex")
grouped["age"].agg(np.max)
Out[71]:
sex
female 35.0
male 30.0
Name: age, dtype: float64
#grouped.age.max()
grouped = user_info.groupby(["sex", "age"])
rs = grouped.agg(len) #grouped.count()
rs
Out[72]:
city income
sex age
female 30.0 1 1
35.0 1 1
male 18.0 2 2
30.0 1 1
如果是根据多个键来进行聚合,默认情况下得到的结果是一个多层索引结构。有两种方式可以避免出现多层索引,先来介绍第一种。对包含多层索引的对象调用 reset_index 方法。
#避免多层索引
# 方式一
rs.reset_index()
Out[73]:
sex age city income
0 female 30.0 1 1
1 female 35.0 1 1
2 male 18.0 2 2
3 male 30.0 1 1
另外一种方式是在分组时,设置参数 as_index=False
# 方式二
grouped = user_info.groupby(["sex", "age"], as_index=False)
grouped.agg(len)
Out[74]:
sex age city income
0 female 30.0 1 1
1 female 35.0 1 1
2 male 18.0 2 2
3 male 30.0 1 1
Series 和 DataFrame 都包含了 describe 方法,我们分组后一样可以使用 describe 方法来查看数据的情况。
grouped = user_info.groupby("sex")
grouped.describe()
Out[75]:
age ... income
count mean std min ... 25% 50% 75% max
sex ...
female 2.0 32.5 3.535534 30.0 ... 7250.0 7500.0 7750.0 8000.0
male 3.0 22.0 6.928203 18.0 ... 3500.0 4000.0 6000.0 8000.0
[2 rows x 16 columns]
2.1 一次应用多个聚合操作
有时候进行分组后,不单单想得到一个统计结果,有可能是多个。比如想统计出不同性别下的一个收入的总和和平均值。
grouped = user_info.groupby("sex")
grouped["income"].agg([np.sum, np.mean])
Out[76]:
sum mean
sex
female 15000 7500
male 15000 5000
2.2 对DataFrame列应用不同的聚合操作
有时候可能需要对不同的列使用不同的聚合操作。例如,想要统计不同性别下人群的年龄的均值以及收入的总和。
grouped = user_info.groupby("sex")
grouped.agg({"age": np.mean, "income": np.sum}).rename(columns={"age": "age_mean", "income": "income_sum"})
Out[77]:
age_mean income_sum
sex
female 32.5 15000
male 22.0 15000
3.transform 操作
前面进行聚合运算的时候,得到的结果是一个以分组名作为索引的结果对象。虽然可以指定 as_index=False ,但是得到的索引也并不是元数据的索引。如果我们想使用原数组的索引的话,就需要进行 merge 转换。
transform方法简化了这个过程,它会把 func 参数应用到所有分组,然后把结果放置到原数组的索引上(如果结果是一个标量,就进行广播)
# 通过 agg 得到的结果的索引是分组名
grouped = user_info.groupby("sex")
grouped["income"].agg(np.mean)
Out[78]:
sex
female 7500
male 5000
Name: income, dtype: int64
# 通过 transform 得到的结果的索引是原始索引,它会将得到的结果自动关联上原始的索引
grouped = user_info.groupby("sex")
grouped["income"].transform(np.mean)
Out[79]:
name
Tom 5000.0
Bob 5000.0
Mary 7500.0
James 5000.0
Andy NaN
Alice 7500.0
Name: income, dtype: float64
#可以看到,通过 transform 操作得到的结果的长度与原来保持一致。
4. apply 操作
除了 transform 操作外,还有更神奇的 apply 操作。
apply 会将待处理的对象拆分成多个片段,然后对各片段调用传入的函数,最后尝试用 pd.concat() 把结果组合起来。func 的返回值可以是 Pandas 对象或标量,并且数组对象的大小不限。
#使用 apply 来完成上面的聚合
grouped = user_info.groupby("sex")
grouped["income"].apply(np.mean)
Out[80]:
sex
female 7500.0
male 5000.0
Name: income, dtype: float64
#来看下 apply 不一样的用法吧。
#比如想要统计不同性别最高收入的前n个值,可以通过下面这种方式实现。
def f1(ser, num=2):
return ser.nlargest(num).tolist()
grouped["income"].apply(f1)
Out[82]:
sex
female [8000, 7000]
male [8000, 4000]
Name: income, dtype: object
#另外,如果想要获取不同性别下的年龄的均值,通过 apply 可以如下实现。
def f2(sex):
return sex.age.mean()
user_info.groupby('sex').apply(f2)
Out[83]:
sex
female 32.5
male 22.0
dtype: float64
grouped.apply(f2)
Out[84]:
sex
female 32.5
male 22.0
dtype: float64
Pandas系列(九)-分组聚合详解的更多相关文章
- ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借
ASP.NET MVC深入浅出系列(持续更新) 一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...
- Hexo系列(三) 常用命令详解
Hexo 框架可以帮助我们快速创建一个属于自己的博客网站,熟悉 Hexo 框架提供的命令有利于我们管理博客 1.hexo init hexo init 命令用于初始化本地文件夹为网站的根目录 $ he ...
- Signalr系列之虚拟目录详解与应用中的CDN加速实战
目录 对SignalR不了解的人可以直接移步下面的目录 SignalR系列目录 前言 前段时间一直有人问我 在用SignalR 2.0开发客服系统[系列1:实现群发通讯]这篇文章中的"/Si ...
- 转载爱哥自定义View系列--文字详解
FontMetrics FontMetrics意为字体测量,这么一说大家是不是瞬间感受到了这玩意的重要性?那这东西有什么用呢?我们通过源码追踪进去可以看到FontMetrics其实是Paint的一个内 ...
- 转载爱哥自定义View系列--Paint详解
上图是paint中的各种set方法 这些属性大多我们都可以见名知意,很好理解,即便如此,哥还是带大家过一遍逐个剖析其用法,其中会不定穿插各种绘图类比如Canvas.Xfermode.ColorFilt ...
- kubernetes系列07—Pod控制器详解
本文收录在容器技术学习系列文章总目录 1.Pod控制器 1.1 介绍 Pod控制器是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试 进行重启,当根据重启策略无 ...
- elasticsearch系列二:索引详解(快速入门、索引管理、映射详解、索引别名)
一.快速入门 1. 查看集群的健康状况 http://localhost:9200/_cat http://localhost:9200/_cat/health?v 说明:v是用来要求在结果中返回表头 ...
- Cobaltstrike系列教程(三)-beacon详解
0x000--前文 Cobaltstrike系列教程(一)-简介与安装 Cobaltstrike系列教程(二)-Listner与Payload生成 heatlevel 0x001-Beacon详解 1 ...
- CSS系列 (05):浮动详解
浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止.由于浮动框不在文档的普通流中,所以文档的普通流中的块框表现得就像浮动框不存在一样. -- W3C 文字环绕 float可以 ...
随机推荐
- QQ邮箱开启SMTP方法如何授权
步骤一: 在打开的邮箱中心,进入设置 步骤二 从邮箱设置中心,进入帐户 步骤三 在这里可以看到POP3/SMTP服务被关闭了,因此客户端会收不到邮件,我们来开启它,查看该服务为已开启时,就可以用客户端 ...
- shell脚本批量推送公钥
目的:新建管理机,为了实现批量管理主机,设置密匙登陆 原理:.通过密钥登陆,可以不用密码 操作过程: 1.生成密匙 ssh-keygen 2.查看密匙 ls ~/.ssh/ 有私匙id_rsa公匙 ...
- C#如何生成JSON字符串提交给接口(服务器)
C#如何生成JSON字符串提交给接口(服务器) 第一章:C#如何拿到从http上返回JSON数据? 第二章:C#如何解析JSON数据?(反序列化对象) 第三章:C#如何生成JSON字符串?(序列化 ...
- SQL语句中不同的连接JOIN
为了从两个表中获取数据,我们有时会用JOIN将两个表连接起来.通常有以下几种连接方式: JOIN or INNER JOIN(内连接) : 这两个是相同的,要求两边表同时有对应的数据,返回行,任何 ...
- LeetCode算法题-Sum of Square Numbers(Java实现)
这是悦乐书的第276次更新,第292篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第144题(顺位题号是633).给定一个非负整数c,判断是否存在两个整数a和b,使得a的 ...
- Spring类型转换(Converter)
Spring的类型转换 以前在面试中就有被问到关于spring数据绑定方面的问题,当时对它一直只是朦朦胧胧的概念,最近稍微闲下来有时间看了一下其中数据转换相关的内容,把相应的内容做个记录. 下面先说明 ...
- MySQL之数据备份、pymysql模块
一 IDE工具介绍 生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具 下载链接:https://pan.baidu.com/s/1bpo5mqj 掌握: #1. 测试+链接 ...
- zabbix,php,nginx,mysql源码安装 神仙操作
→软件包 mkdir /soft/ cd /soft ♦下载以下软件包 nginx-1.14.2.tar.gz wget http://nginx.org/download/nginx-1.14.2. ...
- Shiro学习(一)——Shiro简介
Apache Shiro是Java的一个安全框架.目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大 ...
- iOS开发基础-九宫格坐标(4)
对iOS开发基础-九宫格坐标(3)的代码进行进一步优化. 新建一个 UIView 的子类,并命名为 WJQAppView ,将 appxib.xib 中的 UIView 对象与新建的视图类进行关联. ...