我有一个不可预测的现金流量和不可预测的周期长度的 DataFrame,我需要生成一个向后看的 IRR。
使用求解器在 Excel 中执行此操作非常简单,想知道是否有在 Python 中完成此操作的好方法。 (我想我可以利用 openpyxl 让求解器在 excel 中从 python 工作,但这感觉不必要地麻烦)。
问题很简单:
NPV of Cash Flow = ((cash_flow)/(1+IRR)^years_ago)
目标:找到 SUM(NPV) = 0 的 IRR
我的数据框看起来像这样:
cash_flow |years_ago
-----------------------
-3.60837e+06 |4.09167
31462 |4.09167
1.05956e+06 |3.63333
-1.32718e+06 |3.28056
-4.46554e+06 |3.03889
似乎其他 IRR 计算器(如 numpy.irr)假设严格的周期截止(每 3 个月、1 年等),这是行不通的。另一种选择似乎是迭代路线,我不断地猜测、检查和迭代,但这感觉像是解决这个问题的错误方法。理想情况下,我正在寻找可以做到这一点的东西:
irr = calc_irr((cash_flow1,years_ago1),(cash_flow2,years_ago2),etc)
编辑:这是我运行问题的代码。我有一个事务列表,我选择了按 ID 创建临时表。
for id in df_tran.id.unique():
temp_df = df_tran[df_tran.id == id]
cash_flow = temp_df.cash_flows.values
years = temp_df.years.values
print(id, cash_flow)
print(years)
#irr_calc = irr(cfs=cash_flow, yrs=years,x0=0.100000)
#print(sid, irr_calc)
df_tran(temp_df 所基于的)看起来像:
cash_flow |years |id
0 -3.60837e+06 4.09167 978237
1 31462 4.09167 978237
4 1.05956e+06 3.63333 978237
6 -1.32718e+06 3.28056 978237
8 -4.46554e+06 3.03889 978237
10 -3.16163e+06 2.81944 978237
12 -5.07288e+06 2.58889 978237
14 268833 2.46667 978237
17 -4.74703e+06 1.79167 978237
20 -964987 1.40556 978237
22 -142920 1.12222 978237
24 163894 0.947222 978237
26 -2.2064e+06 0.655556 978237
27 1.23804e+06 0.566667 978237
29 180655 0.430556 978237
30 -85297 0.336111 978237
34 -2.3529e+07 0.758333 1329483
36 21935 0.636111 1329483
38 -3.55067e+06 0.366667 1329483
41 -4e+06 4.14167 1365051
temp_df 看起来与 df_tran 相同,除了它只保存单个 id 的交易。
最佳答案
您可以使用 scipy.optimize.fsolve
:
Return the roots of the (non-linear) equations defined by func(x) = 0 given a starting estimate.
首先定义将作为fsolve
的func
参数的函数。这是您的 IRR、现金流量和年限的 NPV。 (用 NumPy 向量化。)
import numpy as np
def npv(irr, cfs, yrs):
return np.sum(cfs / (1. + irr) ** yrs)
一个例子:
cash_flow = np.array([-2., .5, .75, 1.35])
years = np.arange(4)
# A guess
print(npv(irr=0.10, cfs=cash_flow, yrs=years))
0.0886551465064
现在使用fsolve
:
from scipy.optimize import fsolve
def irr(cfs, yrs, x0):
return np.asscalar(fsolve(npv, x0=x0, args=(cfs, yrs)))
您的 IRR 是:
print(irr(cfs=cash_flow, yrs=years, x0=0.10))
0.12129650313214262
并且您可以确认这会让您的 NPV 为 0:
res = irr(cfs=cash_flow, yrs=years, x0=0.10)
print(np.allclose(npv(res, cash_flow, years), 0.))
True
所有代码放在一起:
import numpy as np
from scipy.optimize import fsolve
def npv(irr, cfs, yrs):
return np.sum(cfs / (1. + irr) ** yrs)
def irr(cfs, yrs, x0, **kwargs):
return np.asscalar(fsolve(npv, x0=x0, args=(cfs, yrs), **kwargs))
要使其与您的 Pandas 示例兼容,只需使用
cash_flow = df.cash_flow.values
years = df.years_ago.values
更新:您问题中的值似乎有点荒谬(如果 IRR 存在的话,您的 IRR 将是一个天文数字)但这是您的运行方式:
cash_flow = np.array([-3.60837e+06, 31462, 1.05956e+06, -1.32718e+06, -4.46554e+06])
years_ago = np.array([4.09167, 4.09167, 3.63333, 3.28056, 3.03889])
print(irr(cash_flow, years_ago, x0=0.10, maxfev=10000))
1.3977721900669127e+82
第二次更新:您的代码中有几个小拼写错误,您的实际 $ 流量和时间计算得出荒谬的 IRR,但下面是您要执行的操作。例如,请注意您有一个 id 和一个单一的负交易,一个负无限的 IRR。
for i, df in df_tran.groupby('id'):
cash_flow = df.cash_flow.values
years = df.years.values
print('id:', i, 'irr:', irr(cash_flow, years, x0=0.))
id: 978237 irr: 347.8254979851405
id: 1329483 irr: 3.2921314448062817e+114
id: 1365051 irr: 1.0444951674872467e+25
关于python - 在 Python (pandas) 中计算可变现金流 IRR,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46203735/