Как насчет корректировки начальных начальных и конечных значений, а не только денежных потоков?

я есть DataFrame с непредсказуемыми денежными потоками и непредсказуемой продолжительностью периода, и мне нужно сгенерировать обратный IRR.

Делать это в Excel довольно просто, используя решатель, задаваясь вопросом, есть ли хороший способ осуществить это в Python. (Я думаю, что я мог бы использовать openpyxl, чтобы заставить решатель работать в Excel из python, но это кажется излишне громоздким).

Проблема довольно проста:

NPV денежного потока = ((cash_flow) / (1 + IRR) ^ years_ago)

ЦЕЛЬ: Найти IRR, где SUM (NPV) = 0

Мой фрейм данных выглядит примерно так:

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)

РЕДАКТИРОВАТЬ: Вот код, из которого я запускаю проблему. У меня есть список транзакций, и я решил создать временные таблицы по идентификатору.

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, за исключением того, что он содержит транзакции только для одного идентификатора.

Ответы на вопрос(1)

Решение Вопроса

scipy.optimize.fsolve:

Вернуть корни (нелинейных) уравнений, определенных func (x) = 0, с учетом начальной оценки.

Сначала определите функцию, которая будетfunc параметр дляfsolve, Это NPV в результате вашего IRR, денежных потоков и лет. (Векторизация с помощью 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

И вы можете подтвердить, что это приводит вас к 0 NPV:

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))

Чтобы сделать это совместимым с вашим примером панд, просто используйте

cash_flow = df.cash_flow.values
years = df.years_ago.values

Обновление: значения в вашем вопросе кажутся немного бессмысленными (ваш 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, но вот что вы хотите сделать ниже. Например, обратите внимание, у вас есть один идентификатор с одной отрицательной транзакцией, отрицательно бесконечный 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
 diogenes05 февр. 2018 г., 10:39
Как насчет корректировки начальных начальных и конечных значений, а не только денежных потоков?

Ваш ответ на вопрос