如何简洁实现非均匀间距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
相关产品推荐
相关产品推荐

