图解pandas的分组groupby机制

8_图解Pandas的groupby机制

在自己的数据处理分析日常中,经常会遇到对数据的某个字段进行分组再求和或均值等其他操作的需求,比如电商中根据不同的支付用户、不同的月份、不同的性别、不同的用户来源进行用户的画像细分,来研究不同组用户的偏好和消费情况等。

在pandas中自己都是使用groupby来解决这类问题,本文结合一份模拟的数据来讲解groupby的内部机制

image

模拟数据

为了方便解释,自己模拟了一份虚拟数据,仅包含3个字段:员工姓名employees、薪资salary、得分score

import pandas as pd
import numpy as np

employees = ["小明","小周","小孙"]   # 4位员工

df=pd.DataFrame({
    "employees":[employees[x] for x in np.random.randint(0,len(employees),9)],  # 在员工中重复选择9个人
    "salary":np.random.randint(800,1000,9),  # 800-1000之间的薪资选择9个数值
    "score":np.random.randint(6,11,9)  # 6-11的分数选择9个
})

df
image

DataFrameGroupBy对象

内部情况

我们现在根据员工进行groupby分组,得到的一个DataFrameGroupBy对象

# groupbying = df.groupby("employees")  by可以省略

groupbying = df.groupby(by="employees")
groupbying
image

那这个DataFrameGroupBy对象到底长的什么样子?我们用list展开看看:

# 查看对象内部的情况

list(groupbying)
image

我们终于看到了这个对象的神秘面目:

  • 对象是一个大列表,里面包含3个元素,每个元素有个元组对象:[tuple1,tuple2,tuple3]
  • 元素就是按照我们指定的员工进行分组:分别是小周、小孙、小明的全部数据信息
image

我们看看小明的具体信息:发现xiaoming是一个元组,转成列表之后看下具体信息:

image

我们发现:元组转成列表后的第一个信息就是分组的员工名,第二个就是这个员工的全部信息构成的一个小DataFrame数据帧。

下面的图形能够很好的展示DataFrameGroupBy对象的内部情况:

image

总结:当我们根据某个字段进行group机制分组的时候,最后能够生成多少个子DataFrame,取决于我们的字段中有多少个不同的元素(案例有3个);当我们分组之后,便可以进行后续的各种聚合操作,比如sum、mean、min等。

遍历DataFrameGroupBy对象

for name,group in groupbying:  # 遍历.DataFrameGroupBy对象
    print(name)
    print(group)
image

选择分组get_group()

对DataFrameGroupBy对象使用get_group()方法,能够让我们得到分组元素中的指定组的数据:

image

同一个列名使用不同聚合函数

分组之后对同一个列名使用不同的函数,函数使用列表形式:下面👇表示的是对score分别求和、最大值、最小值、均值、个数(size)

df9 = df.groupby("employees")["score"].agg(["sum","max","min","mean","size"]).reset_index()
df9
image

聚合函数

相信很多朋友都知道聚合操作或者聚合函数,在SQL中我们可以这样写:

select
    name  -- 姓名
    ,sum(score)  -- 分数最大值
    ,avg(score)  --  平均值
from score
group by name  -- 根据学生姓名分组统计

在上面的SQL语句中,sum和avg就是常见的聚合操作,归类整理下pandas常用的聚合操作:

函数 含义
min/max 最小值、最大值
sum 求和
mean 均值
median 中位数
std 标准差
var 方差
count 计数统计

除了上面的聚合函数,我们还可以使用numpy库的方法,比如unique(不同的元素)、nunique(不同元素的个数,count是统计全部)等,下面会结合实际的例子来说明。

agg聚合操作

聚合操作是通过agg来完成的,可以指定一个列或者多个列分别使用不同的聚合函数来聚合。

1、对单个列进行聚合操作,比如:我们想对salary列求总和sum:

# df.groupby("employees")["salary"].sum  
# 如果只是单个元素,上下两种写法等价
df.groupby("employees").agg({"salary":"sum"})
image

一般情况下,结果是一个以分组字段为行索引的数据帧,那如果我们也想把这个行索引变成数据帧中的一个列名属性,使用reset_index完成:

image

一行代码写作为:

image

2、对多个列使用不同的聚合函数,比如:我们想对salry求和、对score求均值,使用字段对的方式来实现

salary_score = df.groupby("employees").agg({"salary":"sum",
                                            "score":"mean"
                                           })
salary_score
image

同样地,我们可以进行索引重置工作:

image

但是重置之后,我们无法看到具体的聚合函数,考虑给生成的数据帧改下列名,新的名字可以根据自己的喜欢任意指定,一般是要能够代表列名的含义:

image

⚠️前方高能:使用一行代码实现上面的全部过程:

df.groupby("employees").agg({"salary":"sum","score":"mean"}).reset_index().rename(columns={"salary":"salary_sum","score":"score_mean"})
image

详细地解释下上面的一行代码的各个函数功能:

  1. groupby:指定分组的列名字段
  2. agg:指定列名和想实施的聚合函数
  3. reset_index:对生成的数据帧进行索引重置
  4. rename:对生成的列名进行修改;上面是手动指定,需要全部列出来;rename可以对我们想要修改的列名进行重命名

下面的图形的很好地展示从原始数据到DataFrameGroupBy对象,最后再到多个列名聚合的过程:

image

统计列名的非重复个数

在这个需求中我们使用的numpy中的nunqiue方法,给定一个需求:我们想统计每位员工的不同分数以及对应个数。实际的结果应该是:

[图片上传失败...(image-dd4e60-1625708883285)]

1、统计每个员工的不同分数:使用的unique方法

df.groupby("employees").agg({"score":"unique"}).reset_index()

[图片上传失败...(image-19516-1625708883285)]

2、统计每位员工的不同分数个数:使用nunique方法

image

为甚么在这里要特别讲解这两个方法?因为在自己的实际需求中进行遇到,模拟下自己的需求。比如给定一组数据,包含手机订单中的:订单号、型号、厂家

image

现在需要:统计每个型号对应的订单数、厂家名(去重)、厂家数(去重)。这个时候就可以使用上面的方法来实现这个需求,最终的结果应该是这样子:

image

1、先生成订单数和厂家名相关的数据:

image

2、再生成和厂家个数相关的数据:

image

3、通过pandas中的merge函数进行数据的合并:

可以看到下面的数据和实际的结果是一致的

image

一行代码也可以实现上面的需求:对厂家列同时使用两个不同的函数,一个是统计名称,一个是统计个数,结果是一个多重索引的数据帧。

df4.groupby("型号").agg({"订单号":"count","厂家":["unique","nunique"]}).reset_index()
image

transform函数

transform方法解决的是什么问题呢?它和agg又有什么不同呢?我们从一个实际的新需求出发,比如:我们想在数据的后面加上一列,代表的是每位员工的平均得分,数据会变成下面的样子,绿色部分就是我们的需要:

image

好方法:通过transform能够轻松实现上面的需求

df["score_mean"] = df.groupby("employees")["score"].transform("mean")  # transform后面指定需要聚合的函数
df
image

如果不用transform该如何实现上面的需求呢?首先我们还是生成每位员工的平均分数,用字典的形式来表示

image

接下来,我们使用map来进行员工的匹配:

df["score_avg"] = df["employees"].map(avg_score)  # 每位员工和平均值进行匹配
image

transform和agg到底是什么样的区别呢?

image

总结下二者的区别:

  1. transform是在原数据基础上加新的列,agg是根据分组字段和聚合函数生成新的数据帧
  2. transform的数据是填充到分组对象的每列上,agg只是生成了一个最终的聚合结果

总结

在实际的数据处理和统计工作中,分组统计求和、均值、个数等是十分常见的需求,本文结合实际的例子详解了pandas内部的groupby机制,以及如何聚合函数,希望对读者有所帮助。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容