如何按matched分组合并DataFrame行,选取最优hierarchy数据?
问题
需要处理一个包含Id、matched(数值型分组标识)、name、animals、flying、hierarchy(整数优先级,1最优、2次之、3最差)列的pandas DataFrame,需求如下:
- 按
matched字段分组,每个分组保留优先级最高的行;若组内有多个相同最高优先级的行,则全部保留。 - 最高优先级行的缺失字段,用组内其他行的非空值补充。
- 因数据量较大,需避免使用
iterrows()方法,此前尝试列循环的方案要么速度过慢,要么未达到预期效果。
输入示例DataFrame
| Id | matched | name | animals | flying | hierarchy |
|---|---|---|---|---|---|
| 1 | 1 | peter | cow | yes | 1 |
| 2 | 1 | pedro | no | 2 | |
| 3 | 2 | angel | dog | yes | 1 |
| 4 | 3 | joshua | cat | no | 3 |
| 5 | 3 | harry | no | 1 | |
| 6 | 3 | senna | bird | 2 | |
| 7 | 4 | maria | no | 2 | |
| 8 | 4 | juan | no | 3 | |
| 9 | 4 | luis | lama | yes | 2 |
目标输出DataFrame
| Id | matched | name | animals | flying | hierarchy |
|---|---|---|---|---|---|
| 1 | 1 | peter | cow | yes | 1 |
| 3 | 2 | angel | dog | yes | 1 |
| 5 | 3 | harry | bird | no | 1 |
| 7 | 4 | maria | no | 2 | |
| 9 | 4 | luis | lama | yes | 2 |
解决方案
以下方案全程使用pandas向量化操作,避免循环,适合大数据量场景:
1. 预处理空值
先将原始数据中的空字符串转为pd.NA,方便后续缺失值处理:
import pandas as pd # 构造示例数据(实际使用时替换为你的DataFrame) data = { 'Id': [1,2,3,4,5,6,7,8,9], 'matched': [1,1,2,3,3,3,4,4,4], 'name': ['peter','pedro','angel','joshua','harry','senna','maria','juan','luis'], 'animals': ['cow','','dog','cat','','bird','','','lama'], 'flying': ['yes','no','yes','no','no','','no','no','yes'], 'hierarchy': [1,2,1,3,1,2,2,3,2] } df = pd.DataFrame(data) # 空字符串转NA df[['animals', 'flying']] = df[['animals', 'flying']].replace('', pd.NA)
2. 筛选各组最高优先级行
按matched分组,计算每组的最小hierarchy值(对应最高优先级),然后筛选出组内符合该值的行:
# 标记每组最高优先级行 group_min_hierarchy = df.groupby('matched')['hierarchy'].transform('min') top_rows = df[df['hierarchy'] == group_min_hierarchy]
3. 用组内非空值填充缺失字段
按matched分组提取各字段的首个非空值,再填充到筛选出的最高优先级行的缺失位置:
# 生成组内各字段的填充值(取首个非空值) group_fill_values = df.groupby('matched').agg( animals=('animals', lambda x: x.dropna().iloc[0] if not x.dropna().empty else pd.NA), flying=('flying', lambda x: x.dropna().iloc[0] if not x.dropna().empty else pd.NA) ) # 填充缺失值 top_rows = top_rows.set_index('matched').fillna(group_fill_values).reset_index()
4. 整理最终结果
恢复原始列顺序,将pd.NA转回空字符串(与示例输出一致):
# 恢复列顺序并格式化空值 result = top_rows[['Id', 'matched', 'name', 'animals', 'flying', 'hierarchy']].fillna('') print(result)
完整代码
import pandas as pd # 构造示例数据 data = { 'Id': [1,2,3,4,5,6,7,8,9], 'matched': [1,1,2,3,3,3,4,4,4], 'name': ['peter','pedro','angel','joshua','harry','senna','maria','juan','luis'], 'animals': ['cow','','dog','cat','','bird','','','lama'], 'flying': ['yes','no','yes','no','no','','no','no','yes'], 'hierarchy': [1,2,1,3,1,2,2,3,2] } df = pd.DataFrame(data) # 空字符串转NA df[['animals', 'flying']] = df[['animals', 'flying']].replace('', pd.NA) # 筛选最高优先级行 group_min_hierarchy = df.groupby('matched')['hierarchy'].transform('min') top_rows = df[df['hierarchy'] == group_min_hierarchy] # 生成组内填充值并填充 group_fill_values = df.groupby('matched').agg( animals=('animals', lambda x: x.dropna().iloc[0] if not x.dropna().empty else pd.NA), flying=('flying', lambda x: x.dropna().iloc[0] if not x.dropna().empty else pd.NA) ) top_rows = top_rows.set_index('matched').fillna(group_fill_values).reset_index() # 整理结果 result = top_rows[['Id', 'matched', 'name', 'animals', 'flying', 'hierarchy']].fillna('') print(result)
内容的提问来源于stack exchange,提问作者PepperonniCoffee
相关产品推荐
相关产品推荐

