如何在Pandas中对groupby对象的多列应用函数生成新列?
问题描述
现有如下结构的DataFrame:
block lat lon 0 0 112 50 1 0 112 50 2 0 112 50 3 1 105 20 4 1 105 20 5 2 130 30
需要按block列分组后,对每组的lat和lon调用get_location_id(lat, lon)函数(该函数接收经纬度参数,返回单个字符串ID),生成location_id列,要求同一分组的所有行对应相同ID,最终结果如下:
block lat lon location_id 0 0 112 50 1 1 0 112 50 1 2 0 112 50 1 3 1 105 20 23 4 1 105 20 23 5 2 130 30 15
尝试了以下代码但无法运行,且lambda函数无法使用axis=1参数:
df['location_id'] = df.groupby('block').apply(lambda x: get_location_id(x['lat'], x['lon']))
由于数据集较大,希望避免直接对未分组的DataFrame调用该函数,以提升效率。
解决方案
方法1:聚合生成映射表后合并(大数据集首选)
因为同一block内的lat和lon完全一致,我们可以先为每个block生成对应的location_id,得到映射关系后再合并回原DataFrame。这种方式仅需对每个分组调用一次函数,计算效率最高:
# 生成block到location_id的映射 id_mapping = df.groupby('block').apply( lambda group: get_location_id(group['lat'].iloc[0], group['lon'].iloc[0]) ).reset_index(name='location_id') # 合并映射表到原DataFrame df = df.merge(id_mapping, on='block', how='left')
方法2:使用transform直接生成列
如果希望直接在原DataFrame上添加列,可使用transform方法,它会将分组计算的结果自动广播到该分组的所有行,保持索引对齐:
df['location_id'] = df.groupby('block').transform( lambda group: get_location_id(group['lat'].iloc[0], group['lon'].iloc[0]) )
原代码问题说明
原代码中groupby.apply()返回的是一个以block为索引的Series(每个block对应一个ID),直接赋值给df['location_id']会因为索引不匹配导致报错。而上述两种方法都能确保结果与原DataFrame的行一一对应,同时避免重复计算。
内容的提问来源于stack exchange,提问作者thefrollickingnerd
相关产品推荐
相关产品推荐

