如何格式化含大量NaN值的DataFrame,合并非NaN起始行与其余行
合并DataFrame分组中的非NaN行
问题背景
给定如下DataFrame:
import pandas as pd import numpy as np df = pd.DataFrame({ 'col1': [1, np.nan, np.nan, np.nan, 5, np.nan, np.nan, np.nan], 'col2': [np.nan, 2, np.nan, np.nan, np.nan, 6, np.nan, np.nan], 'col3': [np.nan, np.nan, 3, np.nan, np.nan, np.nan, 7, np.nan], 'col4': [np.nan, np.nan, np.nan, 4, np.nan, np.nan, np.nan, 8] })
原始数据展示:
col1 col2 col3 col4 0 1.0 NaN NaN NaN 1 NaN 2.0 NaN NaN 2 NaN NaN 3.0 NaN 3 NaN NaN NaN 4.0 4 5.0 NaN NaN NaN 5 NaN 6.0 NaN NaN 6 NaN NaN 7.0 NaN 7 NaN NaN NaN 8.0
需求:保留所有col1为非NaN的起始行,并将后续对应行的非NaN值合并到这些起始行中,最终得到如下结果:
col1 col2 col3 col4 0 1 2 3 4 4 5 6 7 8
解决方案
方法1:简洁的填充筛选法
利用bfill()向下填充NaN值,再筛选出col1非NaN的行:
# 向下填充NaN,让起始行获取后续行的对应列值 filled_df = df.bfill() # 筛选出col1非NaN的起始行 new_df = filled_df.loc[df['col1'].notna()] print(new_df)
解释:
bfill()会沿着每一列,用下方最近的非NaN值填充当前行的NaN,这样行0会被行1、2、3的col2、col3、col4值填满,行4会被行5、6、7的对应值填满。- 最后通过
df['col1'].notna()筛选出原始的起始行,即可得到目标结果。
方法2:分组聚合法
通过生成分组键,将每组行聚合为一行:
# 生成分组键:col1非NaN的位置累加,形成分组标识 groups = df['col1'].notna().cumsum() # 按分组聚合,取每个列的第一个非NaN值(每组内仅一个有效值) new_df = df.groupby(groups).first() # 将索引替换为原DataFrame中的起始行索引 new_df.index = df[df['col1'].notna()].index print(new_df)
解释:
df['col1'].notna().cumsum()会为每一组起始行+后续行生成相同的分组ID(比如行0-3为1,行4-7为2)。groupby(groups).first()会提取每组内每个列的第一个非NaN值(也就是对应列的唯一有效值)。- 最后替换索引为原起始行的索引,匹配目标结果的格式。
内容的提问来源于stack exchange,提问作者Khaled DELLAL
相关产品推荐
相关产品推荐

