当前位置: 首页 > 后端技术 > Python

Pandas数据分析-超好用Groupby详解

时间:2023-03-26 18:42:57 Python

微信公众号:《Python读钱》有什么问题或者建议欢迎留言公众号在日常的数据分析中,经常需要用到将使用的数据按照某个(多个)字段分成不同的组(groups)进行分析。比如在电商领域,把全国的总销售额按照省份进行划分,分析每个省份销售额的变化。在社交领域,用户根据画像(性别、年龄)进行切分,研究用户的使用习惯和偏好等。在Pandas中,主要是使用groupby来完成上述数据处理操作。本文介绍了groupby的基本原理以及相应的agg、transform、apply操作。为了后续图的方便,使用了10个仿真生成的样本数据。代码和数据如下:company=["A","B","C"]data=pd.DataFrame({"company":[company[x]forxinnp.random.randint(0,len(company),10)],"salary":np.random.randint(5,50,10),"age":np.random.randint(15,50,10)})companysalaryage0C43351C17252C8303A20224B10175B21406A23337C49198B8301.基本原理Groupby的在pandas中实现分组操作的代码非常简单,只需要一行代码。这里将上面的数据集按照公司字段进行划分:[5]中:group=data.groupby("company")将上面的代码输入ipython后,会得到一个DataFrameGroupBy对象。In[6]:groupOut[6]:那么这个生成的DataFrameGroupBy是什么呢?对数据进行groupby之后发生了什么?ipython返回的结果是它的内存地址,不利于直观理解。为了查看组内的内容,这里是将组转换为列表的示例:In[8]:list(group)Out[8]:[('A',companysalaryage3A20226A2333),('B',公司薪资年龄4B10175B21408B830),('C',公司薪资年龄0C43351C17252C8307C4919)]转换成列表形式后,可以看到列表由三个元组组成,每个元组中,第一个元素是一个组(这里是按公司分组的,所以最后一个被划分分为A、B、C),第二个元素是对应group下的DataFrame,整个过程可以如下图说明:总结起来,groupby的过程就是根据groupby的字段对原始DataFrame进行划分(这里是company),分成几个分组的DataFrames,有多少分组DataFrames就有多少分组。所以groupby之后的一系列操作(如agg、apply等)都是基于子DataFrame的操作。了解了这些,我们就基本搞清楚了Pandas中groupby操作的主要原理。下面说说groupby之后的常用操作。2.Agg聚合操作聚合操作是groupby之后很常见的操作,会写SQL的朋友应该很熟悉了。聚合操作可用于求和、平均、最大值、最小值等。下表列出了Pandas中常见的聚合操作。函数使用minminimumvaluemaxmaximumsumsummeanmedian中位数stdstandarddeviationvarvariancecountcount对于样本数据集,如果我想求出不同公司员工的平均年龄和平均工资,可以按照下面的代码:在[12]:data.groupby("company").agg('mean')Out[12]:salaryagecompanyA21.5027.50B13.0029.00C29.2527.25如果要对不同的列求不同的值,例如计算不同公司员工的平均年龄和工资中位数,可以使用字典指定聚合操作:在[17]中:data.groupby('company').agg({'salary':'median','age':'mean'})Out[17]:salaryagecompanyA21.527.50B10.029.00C30.027.25agg聚合过程可以说明如下(以第二个例子为例):3.什么样的数据操作变换变换?和ag有什么区别?为了更好的理解transform和agg的区别,下面从实际应用场景来做对比。在上面的agg中,我们学习了如何找到不同公司员工的平均工资。如果我们现在需要在原数据集上增加一列avg_salary,代表员工所在公司的平均工资(同一公司的员工的平均工资相同),那么如何实现呢?如果按照正常的步骤计算,需要先求出不同公司的平均工资,然后根据员工和公司的对应关系填写相应的职位。如果不使用transform,实现代码如下:In[21]:avg_salary_dict=data.groupby('company')['salary'].mean().to_dict()In[22]:data['avg_salary']=data['company'].map(avg_salary_dict)In[23]:dataOut[23]:CompanySalaryAgeAVG_SALARY0C433529.251C1729.252C83029.253A202221.504B101713.005B214013.006A2321.507C4929.258B83013.00:在[24]中:data['avg_salary']=data.groupby('company')['salary'].transform('mean')In[25]:dataOut[25]:companysalaryageavg_salary0C433529.251C172529.252C83029.253A202221.504B101713.005B214013.006A233321.507C491929.258B83013.00下面以图形化的方式看一下groupby后transform的实现过程(为了更直观的展示,图中增加了公司一栏,实际按照上面的代码,只有salary这一列):图中大方框就是transform和agg的区别。对于agg,会直接计算A、B、C公司对应的平均值并返回,而对于transform,会针对每条数据得到对应的结果。同一组中的样本将具有相同的值。计算出组内均值后,将按照原始指标的顺序返回结果。不明白的可以拍下这张图和agg对比一下。4.applyapply应该是你的老朋友了。相比agg和transform,更加灵活,可以传入任意自定义函数,实现复杂的数据操作。在Pandas数据处理三轴——map、apply、applymap详解)中介绍了apply的使用,那么在groupby之后使用apply和之前介绍的有什么区别呢?有区别,但整个实现原理基本相同。两者的区别在于,对于groupby之后的apply,将分组后的子DataFrame作为参数传递给指定函数时,其基本操作单元是DataFrame,而前面介绍的apply的基本操作单元是Series。还是用一个案例来介绍groupby之后apply的使用。假设我现在需要获取各个公司最老员工的数据,如何实现呢?这可以通过以下代码实现:In[38]:defget_oldest_staff(x):...:df=x.sort_values(by='age',ascending=True)...:returndf.iloc[-1,:]...:In[39]:oldest_staff=data.groupby('company',as_index=False).apply(get_oldest_staff)In[40]:oldest_staffOut[40]:companysalaryage0A23331B21402C4335这样就得到了各公司最老员工的数据。整个流程图如下:可以看到,这里apply的原理和上篇介绍的基本一致,只是这里将函数的参数传入FromSeries到分组的DataFrame。最后,关于apply的使用,这里提个小建议。apply虽然具有更大的灵活性,但是apply的运行效率会比agg和transform慢。所以groupby之后agg和transform可以解决的问题优先使用。如果无法解决,则应考虑申请。扫描二维码关注公众号《Python读钱》,干货第一时间获取!