python利用pandas统计分析—groupby()函数的使用

news/2024/5/20 4:02:42/文章来源:https://blog.csdn.net/sodaloveer/article/details/131175166

文章目录

  • 一、groupby使用场景
  • 二、groupby基本原理
  • 三、groupby分组运算
    • 基础聚合操作:只能选择一种聚合操作
    • agg 聚合操作:可以针对同列选择不同聚合方法
    • transform
    • apply
  • 四、groupby分组后去重统计nunique()
  • 五、groupby分组后重命名列名
    • rename()
    • 直接重新命名列名
    • 重命名所有的列名:add_prefix() /add_suffix()


一、groupby使用场景

在日常数据分析中,经常需要将数据根据某个(多个)字段划分为不同群体(group)进行分析,如电商领域将全国的总销售额根据省份进行划分,分析各省销售额的变化情况,社交领域将用户根据画像(性别、年龄)进行细分,研究用户的使用情况和偏好,如电信诈骗领域,研究诈骗用户与非诈骗用户的语音通话行为等。在Pandas中,上述的数据处理操作主要运用groupby完成,这篇文章就介绍一下groupby的基本原理、对应的agg、transform和apply操作、groupby后的去重统计及重命名列名。

二、groupby基本原理

模拟的样本数据

import pandas as pd
import numpy as np
#主叫号码 
calling_nbr=["13389012374","13389012375","13389012376","13389012377","13389012379","13389012378","16758439532","16758439533","16758439534","16758439535","16758439536","16758439537"]   
#对端号码
called_nbr=["14374397533","14374397533","14374397533","15926372438","15926372439"] 
#通话时间
start_date=["20230404","20230406","20230408"]
data=pd.DataFrame({
"calling_nbr":[calling_nbr[x] for x in np.random.randint(0,len(calling_nbr),20)],
"called_nbr":[called_nbr[x] for x in np.random.randint(0,len(called_nbr),20)],
"calling_duration":np.random.randint(10,120,20),
"start_date":[start_date[x] for x in np.random.randint(0,len(start_date),20)]})data

在这里插入图片描述
将上面的样本数据集按照start_date字段划分:

group=data.groupby(["start_date"])
group

会得到一个DataFrameGroupBy对象
在这里插入图片描述

如何理解DataFrameGroupBy?对data进行groupby后发生了什么,ipython所返回的结果是其内存地址,并不利于直观地理解,为了看看group内部究竟是什么,把group转为list的形式看看:

list(group)

在这里插入图片描述
转成列表的形式后,可以看到,列表由三个元组组成,每个元组中,第一元素是组别,这里是按时start_date进行分组,所以最后分为了20230404、20230406、20230408,第二个元素的是对应组别下的DataFrame。

总结:groupby的过程就是将原有的DataFrame按照groupby的字段(这里是start_date),划分为若干个分组DataFrame,被分为多少个组就有多少个分组DataFrame。所以说,在groupby之后的一系列操作(如agg、apply等),均是基于子DataFrame的操作。理解了这点,也就基本摸清了Pandas中的groupby操作的主要原理。


三、groupby分组运算

聚合操作是groupby后非常常见的操作,聚合操作可以用来求和、均值、最大值、最小值等,下面的表格列出了Pandas中常见的聚合操作。

函数作用
min最小值
max最大值
sum求和
mean均值
median中位数
std标准差
var方差
count计数

基础聚合操作:只能选择一种聚合操作

单列分组

1、单组其他所有列
按calling_nbr分组(groupby),获取数据表其他所列的统计值。因为called_nbr和start_date不是数字类型,所以会自动忽略。

data.groupby('calling_nbr').mean()

2、单组单列
按calling_nbr分组(groupby),仅获取calling_duration的平均值。

data.groupby('calling_nbr')['calling_duration'].mean()

3、单组多列
按calling_nbr分组(groupby),获取calling_duration和calling_fee列的平均值。

data.groupby('calling_nbr')[['calling_duration','calling_fee']].mean()

多列分组
1、多组其他所有列
按calling_nbr和start_date分组(groupby),获取数据表其他所列的统计值。只针对数字类型的列。

data.groupby(['calling_nbr','start_date']).mean()

2、多组单列
按calling_nbr和start_date分组(groupby),仅获取calling_duration的平均值。

data.groupby(['calling_nbr','start_date'])['calling_duration'].mean()

3、多组多列
按calling_nbr和start_date分组(groupby),获取calling_duration和calling_fee列的平均值。

data.groupby(['calling_nbr','start_date'])[['calling_duration','calling_fee']].mean()

agg 聚合操作:可以针对同列选择不同聚合方法

单列分组

1、单组单列

一种聚合方法,多种写法

比如求主叫号码通话时长的平均值

data.groupby('calling_nbr').agg({'calling_duration':'mean'})data.groupby('calling_nbr')['calling_duration'].agg(['mean'])

多种聚合方法,多种写法

比如:求主叫号码通话时长的平均值,总和和标准差

data.groupby('calling_nbr').agg({'calling_duration':['mean','sum','std']})
data.groupby('calling_nbr').agg({'calling_duration':['mean',np.sum,'std']})data.groupby('calling_nbr')['calling_duration'].agg([np.mean,np.sum,np.std])
data.groupby('calling_nbr')['calling_duration'].agg([np.mean,'sum',np.std])

2、单组多列

一种聚合方法,多种写法

data.groupby('calling_nbr').agg({'calling_duration':['mean'],'calling_fee':['sum']})data.groupby('calling_nbr')[['calling_duration','calling_fee']].agg(['mean'])

多种聚合方法,多种写法

data.groupby('calling_nbr').agg({'calling_duration':['mean','sum','std'],'calling_fee':['mean','sum','std']})
data.groupby('calling_nbr').agg({'calling_duration':['mean',np.sum,'std'],'calling_fee':['mean',np.sum,'std']})data.groupby('calling_nbr')[['calling_duration','calling_fee']].agg([np.mean,np.sum,np.std])
data.groupby('calling_nbr')[['calling_duration','calling_fee']].agg([np.mean,'sum',np.std])

多列分组

1、多组单列

一种聚合方法,多种写法

比如求主叫号码当天通话时长总和

data.groupby(['calling_nbr','start_date']).agg({'calling_duration':'sum'})data.groupby(['calling_nbr','start_date'])['calling_duration'].agg(['sum'])

多种聚合方法,多种写法

data.groupby(['calling_nbr','start_date']).agg({'calling_duration':'sum','calling_duration':np.mean})data.groupby(['calling_nbr','start_date'])['calling_duration'].agg(['sum',np.mean])

2、多组多列

一种聚合方法,多种写法

data.groupby(['calling_nbr','start_date']).agg({'calling_fee':'mean','calling_duration':'mean'})data.groupby(['calling_nbr','start_date'])[['calling_duration','calling_fee']].agg(['mean'])

多种聚合方法,多种写法

比如求主叫号码不同天的主叫次数和平均通话时长,代码如下:

data.groupby(['calling_nbr','start_date']).agg({'calling_fee':'count','calling_duration':'mean'})

比如求主叫号码不同天的主叫次数与通话时长的总和、标准差和平均值

data.groupby(['calling_nbr','start_date']).agg({'calling_fee':['sum','count','mean'],'calling_duration':['sum','count','mean']})data.groupby(['calling_nbr','start_date'])[['calling_duration','calling_fee']].agg(['sum','count','mean'])

注意:对于单组单列的分组来说,基础聚合操作与agg聚合操作,得到的对象有什么不同??

  • 基础聚合操作,由于只选择一列数据,所以生成的对象是Series数据结构。
  • agg聚合操作后生成的对象是DataFrame数据结构。
a=data.groupby('calling_nbr')['calling_duration'].mean()
print(type(a))

在这里插入图片描述

a=data.groupby('calling_nbr')['calling_duration'].agg(['mean'])
a=data.groupby('calling_nbr').agg({'calling_duration':'mean'})
print(type(a))

在这里插入图片描述

transform

在agg 聚合中,我们学会了如何求不同主叫号码同一天的平均通话时长,agg 聚合操作形成的新DataFrame,如果现在需要在原数据集中新增加一列avg_calling_duration,代表主叫号码同一天的平均通话时长(相同一天具有一样的平均通话时长)。

如何实现?

1、正常过程:先求得主叫号码不同天的平均通话时长,然后按照主叫号码和通话时间的对应关系填充到对应的位置

avg_calling_duration=data.groupby(['calling_nbr','start_date'])['calling_duration'].mean().rename("avg_calling_duration").reset_index()data_1 = data.merge(mean_calling_duration) 
data_1

在这里插入图片描述

2、使用transform函数,仅需要一行代码

data['avg_calling_duration']=data.groupby(['calling_nbr','start_date'])['calling_duration'].transform('mean')data

在这里插入图片描述

transform与agg对比

  • 对agg而言,会计算得到不同号码当天的通话时长的均值并直接返回。
  • 对transform而言,则会对第每一条数据求得相应的结果,同一组内的样本会有相同的值,组内求完均值后会按照原索引的顺序返回结果。

可以看下图agg与transform过程图解:

在这里插入图片描述

在这里插入图片描述

apply

对于groupby后的apply,以分组后的子DataFrame作为参数传入指定函数的,基本操作单位是DataFrame。

如果现在需要获取当天主叫与同一个被叫号码的通话次数top1的数据,如何实现?

#统计主叫与同一个被叫号码的通话次数
data['calling_called_max']=data.groupby(['calling_nbr','called_nbr','start_date'])['calling_nbr'].transform('count')#统计主叫与同一个被叫号码的通话次数top1
def get_max_calling_called_num(x):df=x.sort_values(by='calling_called_max',ascending=True)return df.iloc[-1:]get_max_calling_called_num_data=data.groupby(['calling_nbr','called_nbr','start_date'],as_index=False).apply(get_max_calling_called_num)

注意:关于apply的使用,这里有个小建议,虽然说apply拥有更大的灵活性,但apply的运行效率会比agg和transform更慢。所以,groupby之后能用agg和transform解决的问题还是优先使用这两个方法,实在解决不了了才考虑使用apply进行操作。


四、groupby分组后去重统计nunique()

nunique():统计groupby()分组后组内不同值的个数,比如适用于统计主叫号码拨打去重后的对端号码个数。

举例1
要求:统计主叫号码拨打去重后的对端号码个数。

#方法二选一。
data.groupby('calling_nbr')['called_nbr'].nunique()
data.groupby('calling_nbr').agg({ "called_nbr": pd.Series.nunique})

在这里插入图片描述

unique()的区别:unique()方法返回的是去重之后的不同值

data.groupby('calling_nbr')['called_nbr'].unique()

在这里插入图片描述


五、groupby分组后重命名列名

groupby分组后对某列进行聚合计算,需要对聚合计算后的新列进行重命名。

  • 第一:先观察数据类型,要转变为DataFrame数据类型,再重命名。
  • 第二:查看groupby后DataFrame.columns是什么格式。
  • 第三:再选择合适的方法进行重命名。

rename()

rename()重命名,reset_index()将DataFrame的索引转成DataFrame的列。

1、对单列进行重命名。

举例1

data_1=data.groupby('calling_nbr').agg({'calling_duration':'mean'})
print(type(data_1)) #查看数据类型
print(data_1.colunms) #查看列名格式

在这里插入图片描述

我们可以看到,是DataFrame数据类型且DataFrame的列名格式是含单元素的列表,可以直接使用rename重命名。

data_1.rename(columns={'calling_duration':'calling_duration_avg'}).reset_index()

举例2

data_1=data.groupby('calling_nbr')['calling_duration'].mean()
print(type(data_1)) #查看数据类型

在这里插入图片描述

我们可以看到,对单列进行聚合得到是Series数据类型,因此先转换成DataFrame数据类型,再重命名。

data_1.to_frame() #将Series数据类型转成DataFrame数据类型。
data_1.rename(columns={'calling_duration':'calling_duration_avg'}).reset_index()

注意:如果是对单列进行聚合得到是Series数据类型,要先转换成DataFrame数据类型,再重命名。

2、对多列进行重命名

举例1

#两种常用的聚合方法,二选一。
data_1=data.groupby('calling_nbr')[['calling_duration','calling_fee']].mean()
data_1=data.groupby('calling_nbr').agg({'calling_duration':'mean','calling_fee':'mean'})

使用这两种方法都可以对多列进行聚合计算,groupby聚合计算后的数据情况如下。
在这里插入图片描述

print(type(data_1)) #查看数据类型

在这里插入图片描述
都是DataFrame数据类型。

print(data_1.columns) #查看列名格式

在这里插入图片描述
DataFrame的列名格式都是含单元素的列表。

我们可以看到,是DataFrame数据类型且DataFrame的列名格式是含单元素的列表,可以直接使用rename()重命名。

data_1.rename(columns={'calling_duration':'calling_duration_avg','calling_fee':'calling_fee_avg'})

举例2

data_1=data.groupby('calling_nbr')[['calling_duration','calling_fee']].agg(['mean'])
data_1

在这里插入图片描述

print(type(data_1)) #查看数据类型

在这里插入图片描述
是DataFrame数据类型。

print(data_1.columns) #查看列名格式

在这里插入图片描述

查看dataframe的列名格式,发现聚合后的列名是MultiIndex类型。此时,必须通过元组的复合索引方式,才能有效提取列的信息。

data_1.columns.values

在这里插入图片描述
查看列名的元素,我们可以看到每个列都是一个元组。通过下面两种方法都可以重命名:

  • 方法一:通过遍历columns的方式,将MultiIndex的一级和二级索引拼接在一起,作为data的新列名。
data_1.columns=[i[0] + "_" + i[1] for i in data_1.columns]
data_1

在这里插入图片描述

  • 方法二:只需要将元组拼接成字符串,然后替换原来的列名就可以了。
data_1.columns = ['_'.join(col).strip() for col in data_1.columns.values]
data_1

在这里插入图片描述

直接重新命名列名

使用"dataframe.columns=[‘新列名’]或dataframe.columns=pd.Series([‘新列名’])" 重命名。

1、要求:对单列进行重命名。

举例1

#对单列进行聚合计算的两种方式,二选一
data_1=data.groupby('calling_nbr').agg({'calling_duration':'mean'})data_1=data.groupby('calling_nbr')['calling_duration'].mean()
data_1.to_frame()#生成是Series数据类型,因此使用to_frame()转换成DataFrame数据类型。
#直接重命名的两种方法,二选一。
data_1.columns = pd.Series(['calling_duration_avg'])
data_1.columns = ['calling_duration_avg']#reset_index()将DataFrame的索引转成DataFrame的列。
data_1.reset_index(inplace=True) 

2、要求:对多列进行重命名。

举例1

#对多列进行聚合计算的两种方式,二选一
data_1=data.groupby('calling_nbr')[['calling_duration','calling_fee']].mean()
data_1=data.groupby('calling_nbr').agg({'calling_duration':'mean','calling_fee':'mean'})
#直接重命名的两种方法,二选一。
data_1.columns = pd.Series(['calling_duration_avg','calling_fee_avg'])
data_1.columns = ['calling_duration_avg','calling_fee_avg']#reset_index()将DataFrame的索引转成DataFrame的列。
data_1.reset_index(inplace=True) 

举例2

data_1=data.groupby('calling_nbr')[['calling_duration','calling_fee']].agg(['mean'])
print(data_1.columns)  #查看列名格式

在这里插入图片描述
聚合后的列名是MultiIndex类型,不能使用"dataframe.columns=[‘新列名’]或dataframe.columns=pd.Series([‘新列名’])" 直接重命名。要多做一个步骤的处理,可以通过遍历columns的方式,先将MultiIndex的一级和二级索引拼接在一起,作为data的新列名或者先将元组拼接成字符串,再替换原来的列名就可以了。(具体例子见rename()目录下“对多列进行重命名”的举例2

注意

  • 对单列进行重命名,注意基础聚合方法:data_1=data.groupby(‘calling_nbr’)[‘calling_duration’].mean()生成的是Series数据类型。
  • 对多列进行重命名,注意agg聚合方法写法:data_1=data.groupby(‘calling_nbr’)[[‘calling_duration’,‘calling_fee’]].agg([‘mean’]),生成的列名格式是MultiIndex类型,不能直接使用rename方法和"dataframe.columns=[‘新列名’]或dataframe.columns=pd.Series([‘新列名’])" 重命名。

重命名所有的列名:add_prefix() /add_suffix()

在处理大量dataframe数据时,我们可能对所有列名进行重命名操作。

pandas.DataFrame.add_prefix() 函数来修改列名的前缀
pandas.DataFrame.add_suffix() 函数来修改列名的后缀
聚合后的列名是MultiIndex类型,不能使用这种方法。

#三种方法达到效果是一致
data_1=data.groupby('calling_nbr').agg({'calling_duration':'mean','calling_fee':'mean'}).add_prefix('new_')data_1=data.groupby('calling_nbr')[['calling_duration','calling_fee']].mean().add_prefix('new_')data_1=data.groupby('calling_nbr').mean().add_prefix('new_')

在这里插入图片描述

参考文章:

https://zhuanlan.zhihu.com/p/101284491
https://blog.csdn.net/qq_39657585/article/details/114789396
https://blog.csdn.net/yeshang_lady/article/details/105345653
https://blog.csdn.net/weixin_43609275/article/details/86220907
https://blog.csdn.net/weixin_39923556/article/details/123002620
https://blog.csdn.net/pz789as/article/details/106059610
https://zhuanlan.zhihu.com/p/358006128

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

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

相关文章

显示GPU进程所属docker 容器

一台服务器,每个人在上面run一个容器,跑各自的代码,虽然通过nvidia-smi可以看到每个进程占用的GPU,但是不好找进程对应的容器id,就没法确认到底是谁占用了较多GPU。 常规操作 通过 nvidia-smi 查看进程占用GPU情况&a…

光模块温度报警的原因及解决措施

光模块是数据中心网络中的关键组件,它们在高温环境下可能会受到影响。如果光模块的温度超过正常范围,可能会导致网络故障和光模块损坏。因此,了解光模块的温度报警并采取相应的解决措施非常重要。 一、光模块温度报警的原因 光模块温度报警通…

LeetCode--HOT100题(45)

目录 题目描述:199. 二叉树的右视图(中等)题目接口解题思路 PS: 题目描述:199. 二叉树的右视图(中等) 给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序…

敏捷开发要点

敏捷开发是一种以人为核心,迭代、增量式的软件开发方法。它强调团队成员的自我管理、面对变化时的快速适应能力,以及持续的沟通和协作。 以下是敏捷开发的几个要点: 敏捷宣言:敏捷开发遵循敏捷宣言,其中包括四个价值声…

Kafka系列四生产者

文章首发于个人博客,欢迎访问关注:https://www.lin2j.tech 一条消息从生产到发送成功,需要经过多个步骤,多个组件。首先要经过拦截器、序列化器、分区器对消息进行预处理,然后将消息按批次放入缓冲区,之后…

【Python】Python Flask token身份认证(附完整代码)

前言 Python Flask是一个使用Python编写的轻量级Web应用框架,它可以非常方便地搭建Web应用。在Web应用中,经常需要进行身份认证,以确保只有授权用户才能访问某些资源。本文将介绍如何使用token进行身份认证,以及如何在Python Fla…

解决报错“No module named ‘pandas.core.indexes‘”

解决办法: 首先使用看一下你的pandas是不是版本太新了,如果使用2.0.0以上的版本,则会出现这个报错。 可以安装1.x.x的版本。 pip install pandas1.5.3

Ubuntu系统安装VirtualBox后无发安装“增强功能”的解决办法

Ubuntu系统安装VirtualBox后, 在设备选项中点击曾倩功能没有反应,也不能是用多动和剪切板功能,解决办法如下 1. 安装linux-image Terminal执行: sudo apt-get install --reinstall linux-image-$(uname -r) 2. 安装virtualbox-guest-x11 …

java spring cloud 企业工程管理系统源码+二次开发+定制化服务

工程项目各模块及其功能点清单 一、系统管理 1、数据字典:实现对数据字典标签的增删改查操作 2、编码管理:实现对系统编码的增删改查操作 3、用户管理:管理和查看用户角色 4、菜单管理:实现对系统菜单的增删改查操…

电脑批量记账,提高效率和管理质量

在快节奏的商业环境中,记账是一项繁琐但必要的任务。为了提高效率和准确性,越来越多的人和企业寻求电脑批量记账的解决方案。 第一步:首先我们要进入晨曦记账本主页面,并点击“收支类别”在弹出来的文件框里输入好类别&#xff0…

国外地址如何地理编码?Python三行代码解决!

对于单个地址基于Python中的geocoder库获取经纬度非常方便,代码如下: # codingutf-8 import geocoder # 输入地址 address Akala Temple lonLat geocoder.osm(address) print(lonLat.latlng) # 输出结果 [27.8569644, 84.0893767]若地址数量较多&am…

异或^实现数据加密

异或是一种二进制的位运算,符号以 XOR 或 ^ 表示。 1.1运算规则 相同为0,不同为1,即 1 ^ 1 0 0 ^ 0 0 1 ^ 0 1 由运算规则可知,任何二进制数与零异或,都会等于其本身,即 A ^ 0 A。 1.2 异或性质 …

【LeetCode】290. 单词规律

这里写自定义目录标题 2023-8-30 09:34:23 290. 单词规律 2023-8-30 09:34:23 这道题目,我是根据 205. 同构字符串 的思路一样,都转化为另外一个第三方的字符串,在比较翻译过后的语句是不是一样的。 class Solution {public boolean wordP…

性能测试平台RunnerGo

在当今的软件开发环境中,测试是确保产品质量和稳定性的重要环节。RunnerGo是一款基于Go语言研发的轻量级测试平台,以其强大的功能和易用性成为了测试领域的佼佼者。 RunnerGo具有轻量级、全栈式、易用性和高效率等特点,为用户提供了全面的测…

《Kubernetes部署篇:Ubuntu20.04基于containerd部署kubernetes1.24.17集群(多主多从)》

一、架构图 如下图所示: 二、环境信息 1、部署规划主机名K8S版本系统版本内核版本IP地址备注k8s-master-631.24.17Ubuntu 20.04.5 LTS5.15.0-69-generic192.168.1.63master节点 + etcd节点k8s-master-641.24.17Ubuntu 20.04.5 LTS5.15.0-69-generic192.168.1.64master节点 + …

Soul的社交元宇宙之路,还有多远?

在元宇宙概念爆火的当下,以互联网为依托的虚拟社交逐步为用户承载起其空缺的精神交流与寄托,而在这其中,以“跟随灵魂找到你”为Slogan,主打年轻人社交元宇宙平台的APP--Soul则在这条赛道上凭借着独特的风格,逐步突出重…

【python爬虫】3.爬虫初体验(BeautifulSoup解析)

文章目录 前言BeautifulSoup是什么BeautifulSoup怎么用解析数据提取数据 对象的变化过程总结 前言 上一关,我们学习了HTML基础知识,知道了HTML是一种用来描述网页的语言,又了解了HTML的基本结构。 认识了HTML中的常见标签和常见属性&#x…

NMS(非极大值抑制)的 Python 实现

文章目录 1. NMS的步骤2. Python代码 非极大值抑制(Non-Maximum Suppression,NMS)是一种在目标检测中常用的技术。 NMS的目的是消除重叠区域中冗余的边界框,并选择最具代表性的目标作为最终结果。通过调整重叠阈值,可…

wandb安装方法及本地部署教程

文章目录 1 wandb介绍2 wandb安装2.1 注册wandb账号2.2 创建项目并获得密钥2.3 安装wandb并登录 3 wandb本地部署3.1 设置wandb运行模式3.2 云端查看运行数据 4 总结 1 wandb介绍 Wandb(Weights & Biases)是一个用于跟踪、可视化和协作机器学习实验…

TypeScript三种特殊类型

1.any类型 说明:any类型代表着可以赋值任意类型 let nickname:any"王二"nickname15nicknametruenicknameundefinednicknamenullnickname{}2.unknown类型 说明:类似any类型;只是不能赋值到其它类型上;除了any和known。…