【Python从入门到进阶】66、Pandas怎样实现groupby每个分组的apply

embedded/2024/10/19 2:16:05/

接上篇《65、Pandas如何批量拆分与合并Excel文件》
上一篇我们学习了Pandas如何批量拆分与合并Excel文件,本篇我们来学习Pandas怎样实现groupby每个分组的apply

一、Pandas中的groupby方法

1、groupby的基本概念

groupby方法的作用:groupby方法是Pandas库中非常强大的功能之一,它允许我们按照一个或多个键(列)对数据集进行分组。分组后,我们可以对每个组应用聚合函数、转换函数或自定义函数,从而进行更深入的数据分析。

分组后的数据结构:使用groupby方法后,我们得到的是一个GroupBy对象。这个对象并不是直接的数据结构,而是一个中间状态,用于存储分组信息和后续操作。我们需要对GroupBy对象应用聚合函数或转换函数,才能得到最终的结果。

2、groupby的使用示例

(1)示例数据集的创建:

首先,我们创建一个示例数据集,以便进行后续的groupby操作。

python">import pandas as pd  # 创建示例数据集  
data = {  'Category': ['A', 'A', 'B', 'B', 'C', 'C', 'A', 'B', 'C'],  'Values': [10, 15, 10, 20, 30, 25, 20, 35, 40]  
}  
df = pd.DataFrame(data)

(2)按单个列进行分组:

现在,我们按照'Category'列对数据进行分组,并计算每个组的总和。

python"># 按'Category'列分组,并计算总和  
grouped_sum = df.groupby('Category')['Values'].sum()  
print(grouped_sum)

输出:

python">输出:
Category  
A    45  
B    65  
C    95  
Name: Values, dtype: int64

(3)按多个列进行分组:

虽然上面的例子只涉及了一个分组键,但Pandas也支持按多个键进行分组。假设我们有一个额外的'SubCategory'列,我们可以同时按'Category'和'SubCategory'进行分组。

python"># 添加一个'SubCategory'列以演示按多个列分组  
df['SubCategory'] = ['X', 'Y', 'X', 'Y', 'X', 'Y', 'Y', 'X', 'Y']  # 按'Category'和'SubCategory'列分组,并计算总和  
grouped_sum_multi = df.groupby(['Category', 'SubCategory'])['Values'].sum()  
print(grouped_sum_multi)

输出:

python">Category  SubCategory  
A         X              10  Y              35  
B         X              10  Y              55  
C         X              30  Y              65  
Name: Values, dtype: int64

3、groupby的常见操作

(1)分组后的聚合操作:

除了求和(sum)之外,Pandas还支持其他多种聚合操作,如均值(mean)、最大值(max)、最小值(min)等。

python"># 计算每个组的均值  
grouped_mean = df.groupby('Category')['Values'].mean()  
print(grouped_mean)  # 计算每个组的最大值  
grouped_max = df.groupby('Category')['Values'].max()  
print(grouped_max)  # 计算每个组的最小值  
grouped_min = df.groupby('Category')['Values'].min()  
print(grouped_min)

(2)分组后的过滤操作:

有时候,我们可能只想保留满足某些条件的组。这时,我们可以使用filter方法。

python"># 过滤出总和大于40的组  
filtered_groups = df.groupby('Category').filter(lambda x: (x['Values'].sum() > 40))  
print(filtered_groups)

(3)分组后的转换操作:

转换操作与聚合操作类似,但转换操作会返回与原始数据集相同形状的结果。例如,我们可以使用transform方法来计算每个组的平均值,并将这个平均值作为新列添加到原始数据集中。

python"># 计算每个组的平均值,并将其作为新列添加到数据集中  
df['GroupMean'] = df.groupby('Category')['Values'].transform('mean')  
print(df)

输出:

python">Category  Values SubCategory  GroupMean  
0        A      10           X        15.0  
1        A      15           Y        15.0  
2        B      10           X        21.666667  
3        B      20           Y        21.666667  
4        C      30           X        28.333333  
5        C      25           Y        28.333333  
6        A      20           Y        15.0  
7        B      35           X        21.666667  
8        C      40           Y        28.333333

通过以上示例和解释,大家应该对Pandas中的groupby方法有了更深入的理解。在实际的数据分析中,groupby方法将是一个非常有用的工具。

二、Pandas中的apply方法

1、apply的基本概念

(1)apply方法的作用:

apply方法是Pandas库中一个非常灵活且强大的工具,它允许我们将自定义的函数应用于DataFrame的行或列,或者应用于groupby分组后的数据。这种灵活性使得apply方法在处理复杂数据操作时变得非常有用。

(2)apply方法的参数:

●func:要应用的函数。这个函数可以是Python的内置函数,也可以是用户自定义的函数。
●axis:指定函数应用的轴向。axis=1表示对行应用函数,axis=0(默认值)表示对列应用函数。如果apply是在groupby对象上调用,则此参数通常不需要指定,因为函数会自动应用于每个分组。
●args和**kwargs:传递给函数的额外参数(位置参数和关键字参数)。
(2)apply方法的返回值:
●当对DataFrame的行或列应用函数时,返回值是一个新的Series(如果axis=1)或DataFrame(如果axis=0,且函数返回多个值)。
●当对groupby分组后的数据应用函数时,返回值通常是一个Series(如果函数返回单个值)或DataFrame(如果函数返回多个值,且使用了result_type='expand'参数)。

2、apply的使用示例

(1)对DataFrame的行应用自定义函数:

python">假设我们有一个DataFrame,并且我们希望对每一行应用一个自定义函数来计算某些值的和。
import pandas as pd  # 创建示例DataFrame  
df = pd.DataFrame({  'A': [1, 2, 3],  'B': [4, 5, 6],  'C': [7, 8, 9]  
})  # 自定义函数:计算每行的和  
def row_sum(row):  return row.sum()  # 对每一行应用自定义函数  
row_sums = df.apply(row_sum, axis=1)  
print(row_sums)

输出:

python">0    12  
1    15  
2    18  
dtype: int64

(2)对DataFrame的列应用自定义函数:

有时,我们可能希望对每一列应用一个函数,比如计算每列的平均值(尽管Pandas已经提供了内置方法mean()来计算平均值,但这里为了演示apply的使用,我们还是自定义一个函数)。

python"># 自定义函数:计算平均值  
def custom_mean(column):  return column.mean()  # 对每一列应用自定义函数  
column_means = df.apply(custom_mean)  
print(column_means)

输出:

python">A    2.0  
B    5.0  
C    8.0  
dtype: float64

(3)对groupby分组后的数据应用自定义函数:

groupbyapply的结合使用是Pandas中非常强大的功能之一。我们可以对分组后的数据应用自定义函数来进行复杂的计算。

python"># 对'A'列进行分组,并对每个组应用自定义函数来计算B列和C列的和  
grouped_sums = df.groupby('A').apply(lambda x: x['B'].sum() + x['C'].sum())  
print(grouped_sums)

输出:

python">A  
1    11  
2    13  
3    15  
dtype: int64

在这个例子中,我们首先对'A'列进行了分组,然后对每个分组应用了一个lambda函数,该函数计算了B列和C列的和。注意,这里的返回值是一个Series,其索引是分组键的值。

如果我们希望返回一个包含多个列的DataFrame,我们可以使用result_type='expand'参数,但需要注意自定义函数的返回值必须是一个能够转换为DataFrame的结构(如Series列表或字典列表)。

python"># 自定义函数:返回包含两列的DataFrame  
def custom_func(group):  sum_bc = group['B'].sum() + group['C'].sum()  mean_bc = group[['B', 'C']].mean().sum()  return pd.DataFrame({'Sum_BC': [sum_bc], 'Mean_BC': [mean_bc]})  # 对每个分组应用自定义函数,并展开结果  
grouped_expanded = df.groupby('A').apply(custom_func, result_type='expand')  
print(grouped_expanded)

输出:

python">Sum_BC  Mean_BC  
A                    
1       11      7.5  
2       13      9.0  
3       15     10.5

在这个例子中,自定义函数返回了一个包含两列的DataFrame,并且我们使用了result_type='expand'参数来将结果展开为一个新的DataFrame。

三、结合groupbyapply的实战案例

案例一:按类别计算平均值并应用自定义函数

1、数据准备:

我们假设有一个销售数据集,其中包含产品类别、销售量和销售价格。

python">import pandas as pd  # 创建示例DataFrame  
data = {  'Category': ['Electronics', 'Electronics', 'Furniture', 'Furniture', 'Clothing'],  'Sales': [150, 200, 300, 400, 250],  'Price': [20, 25, 50, 60, 40]  
}  
df = pd.DataFrame(data)

2、使用groupby按类别分组:

python">grouped = df.groupby('Category')

3、使用apply计算平均值并应用自定义函数进行格式化:

我们想要计算每个类别的平均销售量和平均价格,并且希望将价格格式化为带有两位小数的字符串。

python"># 自定义函数:计算平均值并格式化价格  
def calculate_averages_and_format(group):  averages = group[['Sales', 'Price']].mean()  averages['Formatted_Price'] = averages['Price'].map('{:.2f}'.format)  return averages  # 应用自定义函数  
result_case1 = grouped.apply(calculate_averages_and_format).reset_index()  
print(result_case1)

输出:

python">Category  Sales  Price Formatted_Price  
0  Clothing  250.0   40.0          40.00  
1  Electronics  175.0   22.5          22.50  
2  Furniture  350.0   55.0          55.00

注:紧接着apply方法后面有一个reset_index()方法,这是由于apply方法返回的DataFrame的索引是分组键(在这个例子中是'Category'),reset_index()会将这个索引转换为一个普通的列,并给DataFrame分配一个新的默认整数索引(从0开始的整数索引)。这样做的目的通常是为了使DataFrame的结构更加符合标准形式,便于后续的数据处理和分析。

案例二:对分组数据进行复杂计算

1、数据准备:

仍然使用上面的销售数据集,但这次我们添加了一个新列来表示销售利润(销售量 * 销售价格 - 成本)。

python"># 添加成本列和销售利润列  
data['Cost'] = [15, 20, 40, 50, 30]  
data['Profit'] = data['Sales'] * data['Price'] - data['Cost'] * data['Sales'] / data['Price']  # 简化模型,仅用于演示  
df = pd.DataFrame(data)

2、使用groupby进行分组:

python">grouped = df.groupby('Category')

3、定义一个复杂的计算函数:

我们想要计算每个类别的总利润、平均利润率和总销售量。

python"># 自定义函数:进行复杂计算  
def complex_calculations(group):  total_profit = group['Profit'].sum()  average_profit_margin = (group['Profit'] / (group['Sales'] * group['Price'])).mean()  total_sales = group['Sales'].sum()  return pd.Series({'Total_Profit': total_profit, 'Average_Profit_Margin': average_profit_margin, 'Total_Sales': total_sales})  # 应用复杂计算函数  
result_case2 = grouped.apply(complex_calculations).reset_index()  
print(result_case2)

注意:这里的平均利润率计算是一个简化的模型,仅用于演示。在实际应用中,利润率的计算可能会更加复杂。
输出(具体数值会根据数据计算得出):

python">Category  Total_Profit  Average_Profit_Margin  Total_Sales  
0  Clothing      ...               ...              ...  
1  Electronics   ...               ...              ...  
2  Furniture     ...               ...              ...

案例三:处理分组后的缺失值

1、数据准备(包含缺失值):

我们创建一个新的数据集,其中包含一些缺失值。

python"># 创建包含缺失值的示例DataFrame  
data_with_na = {  'Category': ['Electronics', 'Electronics', 'Furniture', 'Furniture', 'Clothing', 'Clothing'],  'Sales': [150, 200, 300, None, 250, 220],  'Price': [20, 25, None, 60, 40, None]  
}  
df_with_na = pd.DataFrame(data_with_na)

2、使用groupby进行分组:

python">grouped = df_with_na.groupby('Category')

3、定义一个处理缺失值的函数:

我们想要填充缺失的销售量和价格,并计算每个类别的平均销售量和价格。

python"># 自定义函数:处理缺失值并计算平均值  
def handle_missing_values_and_calculate_averages(group):  # 填充缺失值,这里使用列的平均值进行填充(注意:这种方法在实际应用中可能不是最优的,特别是当缺失值较多时)  group['Sales'].fillna(group['Sales'].mean(), inplace=True)  group['Price'].fillna(group['Price'].mean(), inplace=True)  # 计算平均值  averages = group[['Sales', 'Price']].mean()  return averages  # 应用处理缺失值的函数  
result_case3 = grouped.apply(handle_missing_values_and_calculate_averages).reset_index()  
print(result_case3)

在Pandas库中,fillna()函数用于填充DataFrame或Series中的缺失值(NaN)。inplace=True是fillna()函数的一个可选参数,用于控制函数的行为是否直接在原始数据上进行修改,而不是返回一个新的已修改的对象。
注意:使用列的平均值来填充缺失值是一种简单的方法,但在实际应用中可能需要根据数据的具体情况来选择更合适的填充策略。此外,当数据集较大且缺失值较多时,这种方法可能会导致不准确的结果。

输出(具体数值会根据数据计算得出,并且由于填充了缺失值,所以结果可能与原始数据直接计算得出的平均值有所不同):

python">Category  Sales  Price  
0  Clothing  235.0   40.0  
1  Electronics  175.0   22.5  
2  Furniture  300.0   60.0

请注意,由于我们使用了填充缺失值的方法,所以这里的平均销售量和价格是基于填充后的数据计算的。在实际应用中,应该根据数据的具体情况和分析需求来选择最合适的处理方法。

至此,有关Pandas怎样实现groupby每个分组的apply的所有内容介绍完毕,下一篇我们继续学习Pandas使用stack和pivot实现数据透视。

转载请注明出处:https://guangzai.blog.csdn.net/article/details/143057114


http://www.ppmy.cn/embedded/128615.html

相关文章

IBM Flex System服务器硬件监控指标解读

随着企业IT架构的日益复杂,服务器的稳定运行对于保障业务连续性至关重要。IBM Flex System作为一款模块化、可扩展的服务器解决方案,广泛应用于各种企业级环境中。为了确保IBM Flex System服务器的稳定运行,监控易作为一款专业的IT基础设施监…

Golang | Leetcode Golang题解之第473题火柴拼正方形

题目&#xff1a; 题解&#xff1a; func makesquare(matchsticks []int) bool {totalLen : 0for _, l : range matchsticks {totalLen l}if totalLen%4 ! 0 {return false}tLen : totalLen / 4dp : make([]int, 1<<len(matchsticks))for i : 1; i < len(dp); i {dp…

SpringCloud-OpenFeign-服务接口调用

是什么 把需要暴露的api使用接口来暴露&#xff0c;客户端需要调用的时候&#xff0c;直接查看这个接口中有没有就可以了 通用步骤 架构说明 common模块 common 引入 openfeign 新建服务接口类 FeignClient(value "cloud-payment-service") // 服务名 public i…

AdmX_new

0x00前言 因为环境问题&#xff0c;此次靶场都放在vm上。都为NAT模式。 靶机地址: https://download.vulnhub.com/admx/AdmX_new.7z 需要找到两个flag文件。 0x01信息搜集 搜集IP 确认目标IP为172.16.8.131&#xff0c;进一步信息搜集 获取端口开放情况&#xff0c;版本信…

什么是智能合约?

什么是智能合约&#xff1f; 智能合约&#xff0c;就是一段写在区块链上的代码&#xff0c;一旦某个事件触发合约中的条款&#xff0c;代码即自动执行。也就是说&#xff0c;满足条件就执行&#xff0c;不需要人为操控、不需要第三方信任。区块链的安全性和不可篡改性&#xf…

Lua

1.声明一个变量 只要赋值一个变量&#xff0c;就相当于新建了一个变量&#xff0c;默认全局变量&#xff0c;加一个local前缀之后&#xff0c;这个变量就变成了局部变量 a1//全局变量 local b2//局部变量2.nil类型 在Lua里没有被声明过的变量都是nil&#xff0c;nil是一种类…

群晖前面加了雷池社区版,安装失败,然后无法识别出用户真实访问IP

有nas的相信对公网都不模式&#xff0c;在现在基础上传带宽能有100兆的时代&#xff0c;有公网代表着家里有一个小服务器&#xff0c;像百度网盘&#xff0c;优酷这种在线服务都能部署为私有化服务。但现在运营商几乎不可能提供公网ip&#xff0c;要么自己买个云服务器做内网穿…

Linux文件操作基础

目录 Linux文件操作基础 引入 回顾C语言文件操作 系统调用接口 open函数 read函数和write函数 close函数 模拟C语言接口 文件描述符 如何理解Linux下一切皆文件 文本读写与二进制读写 Linux文件操作基础 引入 在Linux第一章提到过&#xff0c;在Linux中&#xff0…