如何在df1的GroupBy.apply中使用df2数据计算加权平均列?
在GroupBy.apply中调用外部DataFrame的解决方案
当然可以在GroupBy.apply()里调用df2的数据!其实GroupBy的apply方法完全支持访问外部变量,只要你在自定义函数里正确传递并引用它就行。不过这里有两种思路,一种是直接用你想尝试的GroupBy.apply,另一种是先预处理df2再合并,后者在数据量大时性能更优,我都给你详细说明:
方法一:直接使用GroupBy.apply调用df2
这种方法适合你想保留分组逻辑的场景,核心是在自定义函数中接收外部的df2,然后针对每个分组的id去df2中筛选对应数据计算加权平均。
假设df2包含value(待加权的数值列)和weight(权重列),示例代码如下:
import pandas as pd # 构造示例数据 df1 = pd.DataFrame({'id': [1, 2, 2, 3, 4]}) df2 = pd.DataFrame({ 'id': [1, 2, 2, 3, 3], 'value': [10, 20, 30, 40, 50], 'weight': [0.3, 0.4, 0.6, 0.2, 0.8] }) def compute_weighted_avg(group, external_df): # 获取当前分组的唯一id(分组后每个组的id是相同的) current_id = group['id'].iloc[0] # 从外部df中筛选对应id的数据 filtered_data = external_df[external_df['id'] == current_id] # 处理权重和为0的边界情况,避免除以0错误 total_weight = filtered_data['weight'].sum() if total_weight == 0: return pd.Series([0.0] * len(group)) # 计算加权平均 weighted_avg = (filtered_data['value'] * filtered_data['weight']).sum() / total_weight # 返回与分组行数一致的Series,确保apply后能匹配到df1的每一行 return pd.Series([weighted_avg] * len(group)) # 给df1新增加权平均列 df1['weighted_average'] = df1.groupby('id').apply(compute_weighted_avg, external_df=df2).reset_index(drop=True)
关键注意点:
- 自定义函数需要返回和分组行数相同的Series,这样apply的结果才能和df1的原始行一一对应
- 记得处理边界情况(比如df2中无对应id、权重和为0),避免报错
方法二:先预处理df2再合并(更高效)
如果你的数据量较大,上面的apply方法因为每次分组都要筛选df2,效率会偏低。更优的做法是先在df2中按id计算好加权平均,再通过merge把结果合并到df1中:
# 先对df2按id预计算加权平均 df2_weighted = df2.groupby('id').apply( lambda x: (x['value'] * x['weight']).sum() / x['weight'].sum() if x['weight'].sum() !=0 else 0.0 ).reset_index(name='weighted_average') # 用左连接合并到df1,保留df1的所有行 df1 = df1.merge(df2_weighted, on='id', how='left') # 处理df2中无对应id的情况(填充NaN为0或其他值) df1['weighted_average'] = df1['weighted_average'].fillna(0.0)
这种方法的优势是只需要对df2做一次分组计算,比循环每个df1的分组要高效得多,推荐在数据量较大时使用。
内容的提问来源于stack exchange,提问作者24n8
相关产品推荐
相关产品推荐

