Расчетный IRR с несогласованными частотами в кадре данных панд - PullRequest
0 голосов
/ 01 ноября 2018

Мои вопросы не о том, как рассчитать IRR (внутренняя норма доходности) , а скорее, учитывая набор данных, аналогичный приведенному ниже, как наилучшим образом рассчитать IRR без ожидания месяцев для результат, когда размер выборки резко увеличивается.

Я использую функцию np.irr

Пример данных

import pandas as pd
import numpy as np

date_list =['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04','2018-01-05', '2018-01-06', '2018-01-07', '2018-01-14','2018-01-21', '2018-01-31','2018-02-08', '2018-02-28']
ids_list = [1,1,1,1,2,2,2,2,3,3,3,3]
flows_list = [ -10, 2, 2, 10, -50, 25, 20, 20, -100, 0,  3, 150]
df = pd.DataFrame(list(zip(date_list,ids_list,flows_list)), columns=['Date','ID','Flow'])
df['Date'] = pd.to_datetime(df['Date'],format='%Y-%m-%d')

Получает набор данных ниже

In [144]: df
Out[144]:
         Date  ID  Flow
0  2018-01-01   1   -10
1  2018-01-02   1     2
2  2018-01-03   1     2
3  2018-01-04   1    10
4  2018-01-05   2   -50
5  2018-01-06   2    25
6  2018-01-07   2    20
7  2018-01-14   2    20
8  2018-01-21   3  -100
9  2018-01-31   3     0
10 2018-02-08   3     3
11 2018-02-28   3   150

Объяснение данных

  1. Date - это день поступления или вывода денежных средств.

  2. ID является уникальным идентификатором каждой сделанной инвестиции.

  3. Flow - это денежный поток ID (инвестиции).

  4. Мне нужно использовать дневную частоту в качестве ввода для np.irr

ЕСЛИ я делаю простой pandas.groupby

In [145]: df.groupby(['ID'])['Flow'].agg(np.irr)
Out[145]:
ID
1    0.141962
2    0.150155
3    0.153450
Name: Flow, dtype: float64

Так что для ID 1 возвращаемое значение np.irr имеет смысл, так как моя частота постоянна.

Однако, в остальном вы увидите, что даты не равны по дням.

Пример вычисления вручную np.irr для идентификатора 3

df.loc[df.ID ==3]['Date'].apply(lambda x: (x - min(df.loc[df.ID ==3]['Date'])).days)

8      0
9     10
10    18
11    38
Name: Date, dtype: int64

Вы можете видеть выше, что каждый денежный поток происходит в начале, 10, 18 и, наконец, в 38 день.

cfs = np.zeros(39)
cfs[[0,10,18,38]] = df.loc[df.ID ==3]['Flow'].values

np.irr(cfs)

Это дает фактические np.irr для ID 3:

Out[155]: 0.011386397119650837

Итак, мой вопрос:

Как рассчитать np.irr по pandas.DataFrame, где частоты денежных потоков не согласованы оптимальным способом?

1 Ответ

0 голосов
/ 06 ноября 2018

Это, кажется, самый оптимальный и точный способ, который я мог найти. Избегать петель !!

Загрузить пример данных

import pandas as pd
import numpy as np

date_list =['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04','2018-01-05', '2018-01-06', '2018-01-07', '2018-01-14','2018-01-21', '2018-01-31','2018-02-08', '2018-02-28']
ids_list = [1,1,1,1,2,2,2,2,3,3,3,3]
flows_list = [ -10, 2, 2, 10, -50, 25, 20, 20, -100, 0,  3, 150]
df = pd.DataFrame(list(zip(date_list,ids_list,flows_list)), columns=['Date','ID','Flow'])
df['Date'] = pd.to_datetime(df['Date'],format='%Y-%m-%d')

Переиндексировать фрейм данных, чтобы включить денежные потоки 0

def reindex_by_date_and_fill(df,groupby_column='ID',value_column='Flow'):
    dates = pd.date_range(df.index.min(), df.index.max())
    return pd.concat([df.reindex(dates)[groupby_column].ffill(),df.reindex(dates,fill_value=0)[value_column]],axis=1)

df_test = df.set_index(['Date']).groupby(['ID'],as_index=False).apply(reindex_by_date_and_fill).reset_index(0,drop=True)

Я получил эту идею из следующих двух постов:

Добавить недостающие даты в пандас-фрейм данных

Даты переиндексации Pandas в Groupby

Обычно он заполняет пропущенные дни и заполняет денежный поток как ноль. Это позволяет вам получать ежедневную частоту по каждой инвестиции, сохраняя при этом период возврата денежных потоков.

In [54]: df_test.head(10)
Out[54]:
             ID  Flow
2018-01-01  1.0   -10
2018-01-02  1.0     2
2018-01-03  1.0     2
2018-01-04  1.0    10
2018-01-05  2.0   -50
2018-01-06  2.0    25
2018-01-07  2.0    20
2018-01-08  2.0     0
2018-01-09  2.0     0
2018-01-10  2.0     0

Позволяет использовать groupby

In [60]: df_test.groupby(['ID'])['Flow'].agg(np.irr)
Out[60]:
ID
1.0    0.141962
2.0    0.082212
3.0    0.011386
Name: Flow, dtype: float64
...