深入理解 Pandas 中的 groupby 函数

groupby 函数是 pandas 库中 DataFrame 和 Series 对象的一个方法,它允许你对这些对象中的数据进行分组和聚合。下面是 groupby 函数的一些常用语法和用法。

对于 DataFrame 对象,groupby 函数的语法如下:

DataFrame.groupby(by=None, axis=0, level=None, as_index=True,
                  sort=True, group_keys=True, squeeze=False, 
                   observed=False, dropna=True) 

其中,各个参数的含义如下:

  • by:用于分组的列名或函数。可以是一个列名、一个函数、一个列表或一个字典。
  • axis:分组轴。如果 axis=0(默认值),则沿着行方向分组;如果 axis=1,则沿着列方向分组。
  • level:在多层索引的情况下,用于指定分组的级别。
  • as_index:是否将分组键作为索引返回。如果 as_index=True(默认值),则返回一个带有分组键作为索引的对象;否则返回一个不带索引的对象。
  • sort:是否对分组键进行排序。如果 sort=True(默认值),则对分组键进行排序;否则不排序。
  • group_keys:是否在结果中包含分组键。如果 group_keys=True(默认值),则在结果中包含分组键;否则不包含。
  • squeeze:是否压缩返回结果。如果 squeeze=True,则尝试压缩返回结果;否则不压缩。
  • observed:是否仅使用观察到的类别进行分组。仅适用于类别类型数据。
  • dropna:是否删除包含缺失值的行。如果 dropna=True(默认值),则删除包含缺失值的行;否则保留。

在数据分析中,我们经常需要对数据进行分组和聚合。例如,我们可能需要计算每个类别中某个变量的平均值、最大值或最小值;或者我们需要对每个类别中的数据进行汇总、统计等操作。在这些情况下,groupby 函数就能派上用场。

例如,假设我们有一个 DataFrame 对象,其中包含了若干个数值列和一个类别列:

import pandas as pd

data = {
    'A': [1, 2, 3, 4],
    'B': [5, 6, 7, 8],
    'C': ['X', 'X', 'Y', 'Y']
}
df = pd.DataFrame(data)

现在,我们想要计算每个类别中 A 列的平均值。我们可以使用 groupby 函数来实现这一点:

result = df.groupby('C')['A'].mean()
print(result)

当我们运行这段代码时,会看到以下输出:

C
X    1.5
Y    3.5
Name: A, dtype: float64

这表明 groupby 函数已经成功地计算了每个类别中 A 列的平均值。

除了计算平均值之外,我们还可以使用 groupby 函数来执行其他操作。例如,我们可以使用它来计算每个类别中 B 列的最大值

result = df.groupby('C')['B'].max()
print(result)

当我们运行这段代码时,会看到以下输出:

C
X    6
Y    8
Name: B, dtype: int64

这表明 groupby 函数已经成功地计算了每个类别中 B 列的最大值。

此外,我们还可以使用 groupby 函数来对数据进行汇总和统计。例如,假设我们想要对每个类别中 A 和 B 列的数据进行汇总,我们可以使用以下代码:

result = df.groupby('C').agg({'A': 'sum', 'B': 'sum'})
print(result)

当我们运行这段代码时,会看到以下输出:

A   B
C
X  3  11
Y  7  15

这表明 groupby 函数已经成功地对每个类别中 A 和 B 列的数据进行了汇总。

如果想要对重复行进行汇聚,并用分号隔开,你可以使用 groupby 函数和 agg 函数来实现这一点。例如,假设我们有一个 DataFrame 对象,其中包含了若干个数值列和一个类别列:

import pandas as pd

data = {
    'A': ['X', 'X', 'Y', 'Y'],
    'B': [1, 2, 3, 4],
    'C': ['M', 'N', 'M', 'N']
}
df = pd.DataFrame(data)

现在,我们想要对 A 列进行分组,并将每组中 C 列的值用分号隔开。我们可以使用 groupby 函数和 agg 函数来实现这一点:

result = df.groupby('A').agg({'C': lambda x: ';'.join(x)})
print(result)

当我们运行这段代码时,会看到以下输出:

C
A
X  M;N
Y  M;N

这表明 groupby 函数和 agg 函数已经成功地对 A 列进行了分组,并将每组中 C 列的值用分号隔开。

总之,groupby 函数是一个非常强大的工具,它允许你快速地对 DataFrame 或 Series 对象中的数据进行分组和聚合。无论你是需要计算统计量,还是需要对数据进行汇总或统计,都可以使用 groupby 函数来完成。

--------------------------------------------------------------------

一、基本用法

先初始化一些数据,方便演示

import pandas as pd

df = pd.DataFrame({
            'name': ['香蕉', '菠菜', '糯米', '糙米', '丝瓜', '冬瓜', '柑橘', '苹果', '橄榄油'],
            'category': ['水果', '蔬菜', '米面', '米面', '蔬菜', '蔬菜', '水果', '水果', '粮油'],
            'price': [3.5, 6, 2.8, 9, 3, 2.5, 3.2, 8, 18],
            'count': [2, 1, 3, 6, 4, 8, 5, 3, 2]
        })
 

按category分组:

grouped = df.groupby('category')
print(type(grouped))
print(grouped)

输出结果:

<class 'pandas.core.groupby.generic.DataFrameGroupBy'>
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x127112df0>


grouped的类型是DataFrameGroupBy,直接尝试输出,打印是内存地址,不太直观,这里写一个函数来展示(可以这么写的原理,后面会介绍)

def view_group(the_pd_group):
    for name, group in the_pd_group:
        print(f'group name: {name}')
        print('-' * 30)
        print(group)
        print('=' * 30, '\n')
view_group(grouped)
 

输出结果

group name: 水果
------------------------------
    name  category  price  count
0   香蕉       水果    3.5      2
6   柑橘       水果    3.2      5
7   苹果       水果    8.0      3
============================== 
group name: 米面
------------------------------
    name  category  price  count
2   糯米       米面    2.8      3
3   糙米       米面    9.0      6
============================== 
group name: 粮油
------------------------------
   name    category  price  count
8  橄榄油       粮油   18.0      2
============================== 
group name: 蔬菜
------------------------------
    name  category  price  count
1   菠菜       蔬菜    6.0      1
4   丝瓜       蔬菜    3.0      4
5   冬瓜       蔬菜    2.5      8
============================== 
 

二、参数源码探析

接下来看一下源码中的方法定义
DataFrame的groupby:

def groupby(
        self,
        by=None,
        axis: Axis = 0,
        level: Level | None = None,
        as_index: bool = True,
        sort: bool = True,
        group_keys: bool = True,
        squeeze: bool | lib.NoDefault = no_default,
        observed: bool = False,
        dropna: bool = True,
    ) -> DataFrameGroupBy:
    pass
 

Series的groupby:

def groupby(
        self,
        by=None,
        axis=0,
        level=None,
        as_index: bool = True,
        sort: bool = True,
        group_keys: bool = True,
        squeeze: bool | lib.NoDefault = no_default,
        observed: bool = False,
        dropna: bool = True,
    ) -> SeriesGroupBy:
    pass
 

Series的groupby函数操作与DataFrame类似,这篇文章只以DataFrame作为示例

入参

by

再来回忆一下基本用法里的写法:

grouped = df.groupby('category')
 

这里传入的category就是第1个参数by,表示要按照什么进行分组,根据官方文档介绍,by可以是mapping, function, label, list of labels中的一种,这里是用的label,也就是说,还可以像下面这样写

  1. label列表

grouped = df.groupby(['category'])
 

2.mapping
这种方式需要按DataFrame的index进行映射,这里把水果蔬菜划分到大组蔬菜水果,米面粮油划分到大组米面粮油

category_dict = {'水果': '蔬菜水果', '蔬菜': '蔬菜水果', '米面': '米面粮油', '粮油': '米面粮油'}
the_map = {}
for i in range(len(df.index)):
    the_map[i] = category_dict[df.iloc[i]['category']]
grouped = df.groupby(the_map)
view_group(grouped)

输出结果如下

group name: 米面粮油
------------------------------
    name  category  price  count
2   糯米       米面    2.8      3
3   糙米       米面    9.0      6
8  橄榄油      粮油   18.0      2
============================== 

group name: 蔬菜水果
------------------------------
    name  category  price  count
0   香蕉       水果    3.5      2
1   菠菜       蔬菜    6.0      1
4   丝瓜       蔬菜    3.0      4
5   冬瓜       蔬菜    2.5      8
6   柑橘       水果    3.2      5
7   苹果       水果    8.0      3
============================== 
 

3.function
这种方式下,自定义函数的入参也是DataFrame的index,输出结果与mapping的例子相同

category_dict = {'水果': '蔬菜水果', '蔬菜': '蔬菜水果', '米面': '米面粮油', '粮油': '米面粮油'}

def to_big_category(the_idx):
    return category_dict[df.iloc[the_idx]['category']]
grouped = df.groupby(to_big_category)
view_group(grouped)
 

axis

axis表示以哪个轴作为分组的切分依据
0 - 等价于index, 表示按行切分,默认
1 - 等价于columns,表示按列切分

这里看一下按列切分的示例

def group_columns(column_name: str):
    if column_name in ['name', 'category']:
        return 'Group 1'
    else:
        return 'Group 2'
# 等价写法 grouped = df.head(3).groupby(group_columns, axis='columns')
grouped = df.head(3).groupby(group_columns, axis=1)
view_group(grouped)
 

输出结果如下:

group name: Group 1
------------------------------
    name  category
0   香蕉       水果
1   菠菜       蔬菜
2   糯米       米面
============================== 

group name: Group 2
------------------------------
   price  count
0    3.5      2
1    6.0      1
2    2.8      3
==============================

相当于把表从垂直方向上切开,左半部分为Group 1,右半部分为Group 2

level
当axis是MultiIndex(层级结构)时,按特定的level进行分组,注意这里的level是int类型,从0开始,0表示第1层,以此类推

构造另一组带MultiIndex的测试数据

the_arrays = [['A', 'A', 'A', 'B', 'A', 'A', 'A', 'B', 'A', 'A'],
              ['蔬菜水果', '蔬菜水果', '米面粮油', '休闲食品', '米面粮油', '蔬菜水果', '蔬菜水果', '休闲食品', '蔬菜水果', '米面粮油'],
              ['水果', '蔬菜', '米面', '糖果', '米面', '蔬菜', '蔬菜', '饼干', '水果', '粮油']]
the_index = pd.MultiIndex.from_arrays(arrays=the_arrays, names=['one ', 'two', 'three'])
df_2 = pd.DataFrame(data=[3.5, 6, 2.8, 4, 9, 3, 2.5, 3.2, 8, 18], index=the_index, columns=['price'])
print(df_2)
 

输出结果如下:

                     price
one  two  three       
A    蔬菜水果 水果       3.5
             蔬菜       6.0
     米面粮油 米面       2.8
B    休闲食品 糖果       4.0
A    米面粮油 米面       9.0
     蔬菜水果 蔬菜       3.0
             蔬菜       2.5
B    休闲食品 饼干       3.2
A    蔬菜水果 水果       8.0
     米面粮油 粮油      18.0
1. 按第3层分组

grouped = df_2.groupby(level=2)
view_group(grouped)

 

输出结果如下:

group name: 水果
------------------------------
                      price
one  two    three       
A    蔬菜水果 水果       3.5
             水果       8.0
============================== 

group name: 米面
------------------------------
                     price
one  two    three       
A    米面粮油 米面       2.8
             米面       9.0
============================== 

group name: 粮油
------------------------------
                      price
one  two    three       
A    米面粮油 粮油      18.0
============================== 

group name: 糖果
------------------------------
                      price
one  two    three       
B    休闲食品 糖果       4.0
============================== 

group name: 蔬菜
------------------------------
                     price
one  two    three       
A    蔬菜水果 蔬菜       6.0
             蔬菜       3.0
             蔬菜       2.5
============================== 

group name: 饼干
------------------------------
                      price
one  two    three       
B    休闲食品 饼干       3.2
==============================
 

共6个分组

2. 按第1, 2层分组

grouped = df_2.groupby(level=[0, 1])
view_group(grouped)

 

输出结果如下:

group name: ('A', '米面粮油')
------------------------------
                      price
one  two    three       
A    米面粮油 米面       2.8
             米面       9.0
             粮油      18.0
============================== 

group name: ('A', '蔬菜水果')
------------------------------
                      price
one  two    three       
A    蔬菜水果 水果       3.5
             蔬菜       6.0
             蔬菜       3.0
             蔬菜       2.5
             水果       8.0
============================== 

group name: ('B', '休闲食品')
------------------------------
                      price
one  two    three       
B    休闲食品 糖果       4.0
             饼干       3.2
============================== 
 

共3个分组,可以看到,分组名称变成了元组

as_index

bool类型,默认值为True。对于聚合输出,返回对象以分组名作为索引

grouped = self.df.groupby('category', as_index=True)
print(grouped.sum())
 

as_index为 True 的输出结果如下:

            price  count
category              
水果         14.7     10
米面         11.8      9
粮油         18.0      2
蔬菜         11.5     13


grouped = self.df.groupby('category', as_index=False)
print(grouped.sum())


as_index为 False 的输出结果如下,与SQL的groupby输出风格相似

    category  price  count
0       水果   14.7     10
1       米面   11.8      9
2       粮油   18.0      2
3       蔬菜   11.5     13
 

sort
bool类型,默认为True。是否对分组名进行排序,关闭自动排序可以提高性能。注意:对分组名排序并不影响分组内的顺序

group_keys
bool类型,默认为True
如果为True,调用apply时,将分组的keys添加到索引中

squeeze
1.1.0版本已废弃,不解释

observed
bool类型,默认值为False
仅适用于任何 groupers 是分类(Categoricals)的
如果为 True,仅显示分类分组的观察值; 如果为 False ,显示分类分组的所有值

dropna
bool类型,默认值为True,1.1.0版本新增参数
如果为 True,且分组的keys中包含NA值,则 NA 值连同行(axis=0)/列(axis=1)将被删除
如果为 False,NA值也被视为分组的keys,不做处理

返回值
DateFrame的gropuby函数,返回类型是DataFrameGroupBy,而Series的groupby函数,返回类型是SeriesGroupBy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/522083.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面试(03)————多线程和线程池

一、多线程 1、什么是线程?线程和进程的区别? 2、创建线程有几种方式 &#xff1f; 3、Runnable 和 Callable 的区别&#xff1f; 4、如何启动一个新线程、调用 start 和 run 方法的区别&#xff1f; 5、线程有哪几种状态以及各种状态之间的转换&#xff1f; 6、线程…

内网穿透的应用-如何在Android Termux上部署MySQL数据库并实现无公网IP远程访问

文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备&#xff0c;尽管最初并非设计为服务器&#xff0c;但是随着技术的进步我们可以将Android配置为生产力工具&#xff0c;变成一个随身…

(十一)RabbitMQ及SpringAMQP

1.初识MQ 1.1.同步和异步通讯 微服务间通讯有同步和异步两种方式&#xff1a; 同步通讯&#xff1a;就像打电话&#xff0c;需要实时响应。 异步通讯&#xff1a;就像发邮件&#xff0c;不需要马上回复。 两种方式各有优劣&#xff0c;打电话可以立即得到响应&#xff0c;…

YOLOV9 + 双目测距

YOLOV9 双目测距 1. 环境配置2. 测距流程和原理2.1 测距流程2.2 测距原理 3. 代码部分解析3.1 相机参数stereoconfig.py3.2 测距部分3.3 主代码yolov9-stereo.py 4. 实验结果4.1 测距4.2 视频展示 相关文章 1. YOLOV5 双目测距&#xff08;python&#xff09; 2. YOLOv7双目…

第十四届蓝桥杯C/C++大学B组题解(一)

1、日期统计 #include <bits/stdc.h> using namespace std; int main() {int array[100] {5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7,5, 9, 5, 0, 3, 8, 7, 5, 8, 1, 5, 8, 6, 1, 8, 3, 0, 3, 7, 9,2, 7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, 9, 4, 4, 6,…

【第十九篇】使用BurpSuite实现XXE+点击劫持(实战案例)

XXE XXE漏洞的原理:攻击者通过注入特殊的XML实体来引用外部资源,比如本地文件系统中的文件。从而读取服务器上的敏感文件。 【1】Burp主动扫描 将条目发送至主动扫描: 仪表盘扫描出XML注入漏洞: 【2】手动测试 原请求包如下: 添加Payload并将 XML 中的数据值替换为我们…

多功能调解室sip可视对讲方案

多功能调解室sip可视对讲方案 人民调解委员会是依法设立的调解民间纠纷的群众性组织。 我国基层解决人民内部纠纷的群众性自治组织.人民调解委员会在城市以居民委员会为单位,农村以村民委员会为单位建立.其任务是: 及时发现纠纷,迅速解决争端.防止矛盾激化,预防,减少犯罪的发生…

EChart简单入门

echart的安装就细不讲了&#xff0c;直接去官网下&#xff0c;实在不会的直接用cdn,省的一番口舌。 cdn.staticfile.net/echarts/4.3.0/echarts.min.js 正入话题哈 什么是EChart&#xff1f; EChart 是一个使用 JavaScript 实现的开源可视化库&#xff0c;Echart支持多种常…

postgresql数据库|数据整合的好工具--Oracle-fdw的部署和使用

概述 Oracle_fdw 是一种postgresql外部表插件&#xff0c;可以读取到Oracle上面的数据。是一种非常方便且常见的pg与Oracle的同步数据的方法 Oracle_fdw 适用场景&#xff1a; Oracle_fdw 是一个开源的 Foreign Data Wrapper (FDW)&#xff0c;主要用于在 PostgreSQL 数据库中…

【2024】Rancher的安装与介绍

———————————————————————————— 记录一下rancher的学习与使用过程 本部分内容包括rancher的介绍、特点、与k8s关系和部署等内容 ———————————————————————————— Rancher是什么&#xff1f; 简单来说&#xff0c;Ranc…

Jackson 2.x 系列【13】特征配置篇之 DeserializationFeature

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Jackson 版本 2.17.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-jaskson-demo 文章目录 1. 前言2. 值处理2.1 USE_BIG_DECIMAL_FOR_FLOATS2.2 USE_BIG_INTEGER_FOR_INTS2…

Qt QML的插件(Qt Quick 2 Extension Plugin)方法

Qt Quick的插件方法 序言环境前置注意概念——Qt Quick插件的相关知识模块名的相关知识模块名本身注意事项模块名版本注意事项 以示例来说明创建插件qmltypes的生成qmltypes的可能性失效 插件的编码注意1、插件模块版本控制2、pro里的注意 调用插件插件信息输入 序言 网上有很…

清明作业 c++

1.封装一个类&#xff0c;实现对一个数求累和阶乘质数 #include <iostream>using namespace std; int mproduct(int a){if(a>1){return a*mproduct((a-1));}else{return 1;} } class number{int a; public:number():a(5){};number(int a):a(a){}void set(int a){thi…

Linux Shell:`awk` 命令

Linux Shell&#xff1a;awk 命令 awk 是一种强大的文本分析工具&#xff0c;广泛用于文本处理、数据提取和报告生成。它使用自己的编程语言来处理文件中的数据。在 Linux Shell 中&#xff0c;awk 命令能够执行复杂的模式匹配、编辑和分析任务。本文将介绍 awk 的基础用法、高…

解锁网络安全新境界:雷池WAF社区版让网站防护变得轻而易举!

网站运营者的救星&#xff1a;雷池WAF社区版 ️ 嘿朋友们&#xff01;今天我超级激动要跟你们分享一个神器——雷池WAF社区版。这个宝贝对我们这帮网站运营者来说&#xff0c;简直就是保护伞&#xff01; 智能语义分析技术&#xff1a;超级侦探上线 先说说为啥我这么稀饭它。雷…

Python项目21:一个简单的记账系统(收入+支出+查询)

------------★Python练手项目源码★------------ Python项目源码20&#xff1a;银行管理系统&#xff08;开户、查询、取款、存款、转账、锁定、解锁、退出&#xff09; Python项目19&#xff1a;学员信息管理系统&#xff08;简易版&#xff09; Python项目18&#xff1a;…

PID控制有物理含义吗

PID控制有物理含义吗 一、背景 对于PID的初学者&#xff0c;经常会有疑惑&#xff0c;为什么位置的误差通过PID就变成了期望速度&#xff1f;他们之间有什么物理关系吗&#xff1f;还有对于无人机&#xff0c;为什么期望升力&#xff0c;又是期望加速度&#xff0c;又是期望油…

DFS(排列数字、飞机降落、选数、自然数的拆分)

注&#xff1a;1.首先要知道退出条件 2.还原现场 典型&#xff1a;全排列 题目1&#xff1a; 代码&#xff1a; #include<bits/stdc.h> using namespace std; int a[1005],p[1005],v[1005]; int n; void dfs(int x) {//此次dfs结束条件,即搜到底 if(xn1){for(int i1;i&…

多线程代码设计模式之单例模式

目录 设计模式引入 饿汉模式 懒汉模式 单例模式总结 设计模式引入 1.1.什么是设计模式 &#xff08;1&#xff09;设计模式就是一种代码的套用模板。例如&#xff1a;一类题型的步骤分别有哪些&#xff0c;是可以直接套用的。 &#xff08;2&#xff09;像棋谱&#xff…

java对象是怎么在jvm中new出来的,在内存中查看java对象成员变量字段属性值

java对象是怎么在jvm中new出来的 查看java对象字段属性在内存中的值 java 对象 创建 流程 附上java源码 public class MiDept {private int innerFiled999;public MiDept() {System.out.println("new MiDept--------------");}public String show(int data) {Sy…