接上篇《65、Pandas如何批量拆分与合并Excel文件》
上一篇我们学习了Pandas如何批量拆分与合并Excel文件,本篇我们来学习Pandas怎样实现groupby每个分组的apply。
一、Pandas中的groupby方法
1、groupby的基本概念
groupby方法的作用:groupby方法是Pandas库中非常强大的功能之一,它允许我们按照一个或多个键(列)对数据集进行分组。分组后,我们可以对每个组应用聚合函数、转换函数或自定义函数,从而进行更深入的数据分析。
分组后的数据结构:使用groupby方法后,我们得到的是一个GroupBy对象。这个对象并不是直接的数据结构,而是一个中间状态,用于存储分组信息和后续操作。我们需要对GroupBy对象应用聚合函数或转换函数,才能得到最终的结果。
2、groupby的使用示例
(1)示例数据集的创建:
首先,我们创建一个示例数据集,以便进行后续的groupby操作。
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'列对数据进行分组,并计算每个组的总和。
# 按'Category'列分组,并计算总和
grouped_sum = df.groupby('Category')['Values'].sum()
print(grouped_sum)
输出:
输出:
Category
A 45
B 65
C 95
Name: Values, dtype: int64
(3)按多个列进行分组:
虽然上面的例子只涉及了一个分组键,但Pandas也支持按多个键进行分组。假设我们有一个额外的'SubCategory'列,我们可以同时按'Category'和'SubCategory'进行分组。
# 添加一个'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)
输出:
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)等。
# 计算每个组的均值
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方法。
# 过滤出总和大于40的组
filtered_groups = df.groupby('Category').filter(lambda x: (x['Values'].sum() > 40))
print(filtered_groups)
(3)分组后的转换操作:
转换操作与聚合操作类似,但转换操作会返回与原始数据集相同形状的结果。例如,我们可以使用transform方法来计算每个组的平均值,并将这个平均值作为新列添加到原始数据集中。
# 计算每个组的平均值,并将其作为新列添加到数据集中
df['GroupMean'] = df.groupby('Category')['Values'].transform('mean')
print(df)
输出:
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的行应用自定义函数:
假设我们有一个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)
输出:
0 12
1 15
2 18
dtype: int64
(2)对DataFrame的列应用自定义函数:
有时,我们可能希望对每一列应用一个函数,比如计算每列的平均值(尽管Pandas已经提供了内置方法mean()来计算平均值,但这里为了演示apply的使用,我们还是自定义一个函数)。
# 自定义函数:计算平均值
def custom_mean(column): return column.mean() # 对每一列应用自定义函数
column_means = df.apply(custom_mean)
print(column_means)
输出:
A 2.0
B 5.0
C 8.0
dtype: float64
(3)对groupby分组后的数据应用自定义函数:
groupby与apply的结合使用是Pandas中非常强大的功能之一。我们可以对分组后的数据应用自定义函数来进行复杂的计算。
# 对'A'列进行分组,并对每个组应用自定义函数来计算B列和C列的和
grouped_sums = df.groupby('A').apply(lambda x: x['B'].sum() + x['C'].sum())
print(grouped_sums)
输出:
A
1 11
2 13
3 15
dtype: int64
在这个例子中,我们首先对'A'列进行了分组,然后对每个分组应用了一个lambda函数,该函数计算了B列和C列的和。注意,这里的返回值是一个Series,其索引是分组键的值。
如果我们希望返回一个包含多个列的DataFrame,我们可以使用result_type='expand'参数,但需要注意自定义函数的返回值必须是一个能够转换为DataFrame的结构(如Series列表或字典列表)。
# 自定义函数:返回包含两列的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)
输出:
Sum_BC Mean_BC
A
1 11 7.5
2 13 9.0
3 15 10.5
在这个例子中,自定义函数返回了一个包含两列的DataFrame,并且我们使用了result_type='expand'参数来将结果展开为一个新的DataFrame。
三、结合groupby和apply的实战案例
案例一:按类别计算平均值并应用自定义函数
1、数据准备:
我们假设有一个销售数据集,其中包含产品类别、销售量和销售价格。
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按类别分组:
grouped = df.groupby('Category')
3、使用apply计算平均值并应用自定义函数进行格式化:
我们想要计算每个类别的平均销售量和平均价格,并且希望将价格格式化为带有两位小数的字符串。
# 自定义函数:计算平均值并格式化价格
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)
输出:
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、数据准备:
仍然使用上面的销售数据集,但这次我们添加了一个新列来表示销售利润(销售量 * 销售价格 - 成本)。
# 添加成本列和销售利润列
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进行分组:
grouped = df.groupby('Category')
3、定义一个复杂的计算函数:
我们想要计算每个类别的总利润、平均利润率和总销售量。
# 自定义函数:进行复杂计算
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)
注意:这里的平均利润率计算是一个简化的模型,仅用于演示。在实际应用中,利润率的计算可能会更加复杂。
输出(具体数值会根据数据计算得出):
Category Total_Profit Average_Profit_Margin Total_Sales
0 Clothing ... ... ...
1 Electronics ... ... ...
2 Furniture ... ... ...
案例三:处理分组后的缺失值
1、数据准备(包含缺失值):
我们创建一个新的数据集,其中包含一些缺失值。
# 创建包含缺失值的示例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进行分组:
grouped = df_with_na.groupby('Category')
3、定义一个处理缺失值的函数:
我们想要填充缺失的销售量和价格,并计算每个类别的平均销售量和价格。
# 自定义函数:处理缺失值并计算平均值
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()函数的一个可选参数,用于控制函数的行为是否直接在原始数据上进行修改,而不是返回一个新的已修改的对象。
注意:使用列的平均值来填充缺失值是一种简单的方法,但在实际应用中可能需要根据数据的具体情况来选择更合适的填充策略。此外,当数据集较大且缺失值较多时,这种方法可能会导致不准确的结果。
输出(具体数值会根据数据计算得出,并且由于填充了缺失值,所以结果可能与原始数据直接计算得出的平均值有所不同):
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