如何按指定公式填充Pandas DataFrame中的NaN中间值?
Pandas DataFrame按自定义递推公式填充NaN值
问题说明
现有DataFrame结构如下:
| value |
|---|
| 30 |
| NaN |
| NaN |
| 25 |
| NaN |
| 20 |
| NaN |
| NaN |
| NaN |
| NaN |
| 15 |
| ... |
需要按以下自定义递推公式填充NaN:当前填充值 = 前一个有效值(或已填充值) - ((前一个值 - 后一个有效值) / 剩余待填充的NaN数量)
示例计算:
- 第一个NaN:
30 - (30-25)/2 = 27.5 - 第二个NaN:
27.5 - (27.5-25)/1 = 25
期望得到的结果:
| value | expected value |
|---|---|
| 30 | 30 |
| NaN | 27.5 |
| NaN | 25 |
| 25 | 25 |
| NaN | 20 |
| 20 | 20 |
| NaN | 18.75 |
| NaN | 17.5 |
| NaN | 16.25 |
| NaN | 15 |
| 15 | 15 |
| ... | ... |
解决方案
通过标记锚点分组+递推计算的方式实现:
import pandas as pd import numpy as np # 构造示例DataFrame df = pd.DataFrame({ 'value': [30, np.nan, np.nan, 25, np.nan, 20, np.nan, np.nan, np.nan, np.nan, 15] }) # 给每个连续NaN区间标记分组ID df['anchor_group'] = df['value'].notna().cumsum() # 提取所有非NaN锚点的位置和数值 anchor_points = df[df['value'].notna()].reset_index() # 遍历每对相邻锚点,填充中间的NaN for i in range(len(anchor_points)-1): start_idx = anchor_points.loc[i, 'index'] end_idx = anchor_points.loc[i+1, 'index'] start_val = anchor_points.loc[i, 'value'] end_val = anchor_points.loc[i+1, 'value'] nan_count = end_idx - start_idx - 1 if nan_count <= 0: continue # 递推生成填充序列 fill_seq = [start_val] current_val = start_val for _ in range(nan_count): remaining_nans = nan_count - len(fill_seq) + 1 step = (current_val - end_val) / remaining_nans current_val -= step fill_seq.append(current_val) # 将填充值写入DataFrame df.loc[start_idx+1:end_idx-1, 'value'] = fill_seq[1:] # 移除临时分组列 df.drop('anchor_group', axis=1, inplace=True) print(df)
代码逻辑解析
- 锚点分组:用
notna().cumsum()给每段连续NaN区间分配唯一分组ID,确保每个区间对应前后两个有效锚点。 - 锚点提取:筛选出所有非NaN值的位置和数值,作为填充的起始和终止参照。
- 递推填充:针对每段NaN区间,按照自定义公式逐步计算每个位置的填充值,每一步都用上一步的结果更新当前值,完全匹配需求中的递推逻辑。
运行结果
执行代码后,df['value']将得到与期望列一致的填充结果:
| index | value |
|---|---|
| 0 | 30.00 |
| 1 | 27.50 |
| 2 | 25.00 |
| 3 | 25.00 |
| 4 | 20.00 |
| 5 | 20.00 |
| 6 | 18.75 |
| 7 | 17.50 |
| 8 | 16.25 |
| 9 | 15.00 |
| 10 | 15.00 |
内容的提问来源于stack exchange,提问作者Nazmi Husaini
相关产品推荐
相关产品推荐

