如何在Pandas DataFrame中按多列分组合并压缩以减少行数
Pandas按ID分组填充NaN并压缩行数的解决方案
需求说明
按id_1和id_2分组,用组内其他行的有效值填充对应列的NaN,最终转换为行数最少的形式,且不丢失数据、不做聚合操作。
原数据示例
import pandas as pd import numpy as np df = pd.DataFrame({ 'id_1': [33,33,33,33,22,22,88,100], 'id_2': [64,64,64,64,12,12,77,100], 'col_1': [np.nan, 'dog', np.nan, 'kangaroo', np.nan, np.nan, np.nan, np.nan], 'col_2': ['bike', 'car', np.nan, np.nan, 'train', np.nan, 'horse', np.nan], 'col_3': [np.nan, np.nan, 'star', 'meteor', np.nan, 'rock', np.nan, np.nan] })
方法一:分组填充后去重(简洁高效)
利用Pandas的ffill(前向填充)和bfill(后向填充),先将组内所有NaN用同组有效值填充,再删除重复行得到最少行数:
# 按ID分组,组内双向填充NaN,然后去重 result = df.groupby(['id_1', 'id_2']).apply(lambda g: g.ffill().bfill()).drop_duplicates().reset_index(drop=True) print(result)
输出结果:
id_1 id_2 col_1 col_2 col_3 0 33 64 dog bike star 1 33 64 kangaroo car meteor 2 22 12 NaN train rock 3 88 77 NaN horse NaN 4 100 100 NaN NaN NaN
方法二:分组提取非空值并对齐(更灵活)
手动提取每组各列的非空值,将列表长度对齐后重组DataFrame,适合需要自定义处理逻辑的场景:
def process_group(g): # 收集每组各列的非空值列表 cols = ['col_1', 'col_2', 'col_3'] col_data = {col: g[col].dropna().tolist() for col in cols} # 确定当前组的最大行数 max_row_count = max(len(v) for v in col_data.values()) # 补全各列列表长度(不足的补NaN) for col in cols: col_data[col] += [np.nan] * (max_row_count - len(col_data[col])) # 添加ID列 col_data['id_1'] = [g['id_1'].iloc[0]] * max_row_count col_data['id_2'] = [g['id_2'].iloc[0]] * max_row_count return pd.DataFrame(col_data) # 应用分组处理并合并结果 result = df.groupby(['id_1', 'id_2'], group_keys=False).apply(process_group).reset_index(drop=True) print(result)
输出结果与方法一完全一致。
内容的提问来源于stack exchange,提问作者scrollout
相关产品推荐
相关产品推荐

