如何无需for循环或iterrows(),基于code列聚合Pandas DataFrame数据
问题场景
假设我们有这样一个Pandas DataFrame(df1),其中同一code对应的多行数据里,每个item列最多只有一个有效数值,其余都是NaN:
import pandas as pd import numpy as np df1 = pd.DataFrame({ 'code': [1111]*11 + [2222]*6, 'item01': [np.nan]*4 + [32] + [np.nan]*6 + [20] + [np.nan]*5, 'item02': [np.nan]*10 + [np.nan]*3 + [7] + [np.nan]*2, 'item03': [np.nan]*17, 'item04': [np.nan]*1 + [650] + [np.nan]*9 + [np.nan]*2 + [5] + [np.nan]*3, 'item05': [440] + [np.nan]*10 + [np.nan]*6 })
它的直观结构如下:
df1
code item01 item02 item03 item04 item05
0 1111 nan nan nan nan 440
1 1111 nan nan nan 650 nan
2 1111 nan nan nan nan nan
3 1111 nan nan nan nan nan
4 1111 32 nan nan nan nan
5 1111 nan nan nan nan nan
6 1111 nan nan nan nan nan
7 1111 nan nan nan nan nan
8 1111 nan nan nan nan nan
9 1111 nan nan nan nan nan
10 1111 nan nan nan nan nan
11 2222 20 nan nan nan nan
12 2222 nan nan nan nan nan
13 2222 nan nan nan 5 nan
14 2222 nan 7 nan nan nan
15 2222 nan nan nan nan nan
16 2222 nan nan nan nan nan
我们需要把它按code聚合,将同一code下的有效数值合并到一行,得到目标df2:
df2
code item01 item02 item03 item04 item05
0 1111 32 nan nan 650 440
1 2222 20 7 nan 5 nan
关键要求是不能用for循环或iterrows(),该怎么实现?
最简解决方案
直接用groupby配合first()方法就能搞定,一行代码解决问题:
df2 = df1.groupby('code', as_index=False).first()
执行后得到的结果完全符合目标df2的结构。
为什么这个方法有效?
groupby('code'):把DataFrame按code的唯一值分组,所有相同code的行会被归为一组。as_index=False:让code保持为普通列,而不是成为结果的索引,这样输出结构和目标一致。first():对每个分组的每一列,提取该列的第一个非NaN值。如果某列全是NaN,就保留NaN——刚好匹配我们的需求,因为每个code分组下每个item列最多只有一个有效数值。
扩展场景:如果同一列有多个有效数值?
如果后续遇到同一code分组下某个item列有多个非NaN值,可以根据业务需求替换聚合方法:
- 求和:用
sum()(自动忽略NaN) - 取均值:用
mean() - 取最后一个有效数值:用
last() - 收集所有有效数值到列表:用
lambda x: x.dropna().tolist()
内容的提问来源于stack exchange,提问作者funyao

