You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何简洁实现非均匀间距Pandas DataFrame的NaN插值补全?

问题

给定包含债券利率的DataFrame,其中存在大量NaN值,列名对应非均匀分布的债券期限,无法直接使用interpolate方法填充。原始数据如下:

timeperiod  cm01  cm03  cm06  cy01  cy02  cy03  cy05  cy07  cy10  cy20  cy30
1962-01-02   NaN   NaN   NaN  3.22   NaN  3.70  3.88   NaN  4.06  4.07   NaN
1962-01-03   NaN   NaN   NaN  3.24   NaN  3.70  3.87   NaN  4.03  4.07   NaN
1962-01-04   NaN   NaN   NaN  3.24   NaN  3.69  3.86   NaN  3.99  4.06   NaN
1962-01-05   NaN   NaN   NaN  3.26   NaN  3.71  3.89   NaN  4.02  4.07   NaN
1962-01-08   NaN   NaN   NaN  3.31   NaN  3.71  3.91   NaN  4.03  4.08   NaN

当前采用逐行循环的方式填充NaN:

terms = np.array([1/12,3/12,6/12,1,2,3,5,7,10,20,30])
term_col = ['cm01', 'cm03', 'cm06', 'cy01', 'cy02', 'cy03', 'cy05', 'cy07', 'cy10', 'cy20', 'cy30']

for i in rf.index:
    d = (rf.loc[i,term_col]).to_numpy(dtype=float)

    spl = CubicSpline(terms[~np.isnan(d)],d[~np.isnan(d)],extrapolate=True)
    rf.loc[i,term_col] = spl(terms)

希望找到更简洁优雅的实现方式,误以为apply无法返回多值且不想使用global变量,特此求助。

优化方案

其实apply完全可以返回多列数据,只要让每行的处理函数返回一个Series即可,这样就能避免循环,实现更简洁的代码:

from scipy.interpolate import CubicSpline
import numpy as np
import pandas as pd

terms = np.array([1/12, 3/12, 6/12, 1, 2, 3, 5, 7, 10, 20, 30])
term_col = ['cm01', 'cm03', 'cm06', 'cy01', 'cy02', 'cy03', 'cy05', 'cy07', 'cy10', 'cy20', 'cy30']

def fill_row(row):
    d = row[term_col].to_numpy(dtype=float)
    valid_mask = ~np.isnan(d)
    # 处理全NaN的极端情况(如果有的话)
    if not valid_mask.any():
        return row
    spl = CubicSpline(terms[valid_mask], d[valid_mask], extrapolate=True)
    row[term_col] = spl(terms)
    return row

# 应用函数到每一行,直接得到填充后的DataFrame
rf_filled = rf.apply(fill_row, axis=1)

说明

  • 利用apply的axis=1参数逐行处理,每行处理函数返回填充后的Series,apply会自动将这些Series组合成完整的DataFrame。
  • 加入了全NaN行的判断,避免出现无有效数据时的报错。
  • 代码结构更紧凑,避免了显式的索引循环,可读性更高。

内容的提问来源于stack exchange,提问作者Gabriella Chaos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 11:13:16