Pandas DataFrame单元格依赖场景下NaN值高效填充方案咨询
解决方案
问题原因
原有代码为整列向量化计算,计算时所有行的PresentValue只有第一行有初始值,后续行均为NaN,且计算过程中不会自动用上一行的FinalPresentValue更新下一行的PresentValue,因此后续列的计算结果全部为NaN。
实现方案
对于这种行级前向依赖的计算,最直观易维护的实现是先计算无依赖的固定列,再逐行迭代计算有依赖的列。你当前的场景只有6行数据,循环计算的性能完全够用。
完整代码
import pandas as pd import numpy as np Initial_Investment = 7.5 * 10**9 # 10^9 ~ 10亿 Initial_Loan = 12.5 * 10**9 Initial_Portfolio_Value = 20 * 10**9 Portfolio_Duration = 10 # 麦考利久期 Initial_Short_Term_Rate = 0.06 Initial_Coupon_Rate = 0.085 Initial_Loan_Rate = 0.07 years = np.arange(1991,1997,1) # 1991-1996 interest_rate_change = np.array([-0.005, -0.005, -0.005, -0.005, 0.02, 0.02]) df = pd.DataFrame({'Year':years, 'PresentValue':np.nan, 'InterestRateChange':interest_rate_change}) # 先计算无前置依赖的列,不需要参与循环 df['ShortTermRates'] = df['InterestRateChange'].shift(1,fill_value=Initial_Short_Term_Rate).cumsum() df['CouponRates'] = df['InterestRateChange'].shift(1,fill_value=Initial_Coupon_Rate).cumsum() df['LoanRates'] = df['InterestRateChange'].shift(1,fill_value=Initial_Loan_Rate).cumsum() df['LoanPayment'] = df['LoanRates'] * -Initial_Loan # 初始化第一行数据 df.loc[0, 'PresentValue'] = Initial_Portfolio_Value df.loc[0, 'DeltaPrice'] = df.loc[0, 'InterestRateChange'] * df.loc[0, 'PresentValue'] * -Portfolio_Duration df.loc[0, 'CouponEarning'] = df.loc[0, 'CouponRates'] * df.loc[0, 'PresentValue'] df.loc[0, 'Earnings/Loss'] = df.loc[0, 'DeltaPrice'] + df.loc[0, 'CouponEarning'] + df.loc[0, 'LoanPayment'] df.loc[0, 'FinalPresentValue'] = df.loc[0, 'PresentValue'] + df.loc[0, 'Earnings/Loss'] # 逐行计算后续行 for i in range(1, len(df)): # 当期现值等于上一期期末现值 df.loc[i, 'PresentValue'] = df.loc[i-1, 'FinalPresentValue'] # 计算当期其他依赖列 df.loc[i, 'DeltaPrice'] = df.loc[i, 'InterestRateChange'] * df.loc[i, 'PresentValue'] * -Portfolio_Duration df.loc[i, 'CouponEarning'] = df.loc[i, 'CouponRates'] * df.loc[i, 'PresentValue'] df.loc[i, 'Earnings/Loss'] = df.loc[i, 'DeltaPrice'] + df.loc[i, 'CouponEarning'] + df.loc[i, 'LoanPayment'] df.loc[i, 'FinalPresentValue'] = df.loc[i, 'PresentValue'] + df.loc[i, 'Earnings/Loss'] print(df.round(2))
扩展说明
如果后续数据量上升到万行以上,可以用numba装饰器加速循环,或者将计算逻辑抽象为累积函数用numpy.frompyfunc实现向量化累积计算,对于小数据量上述循环方案足够简洁易维护。
内容的提问来源于stack exchange,提问作者sir.isaac.newton
相关产品推荐
相关产品推荐

