在 python 中需要帮助计算每项投资在不同日期的不同投资的 IRR
Need help calculating IRR for different investments at different dates for each investment, in python
我需要帮助计算不同投资的内部收益率,以及这些投资在不同时间的内部收益率。
所以有一个数据框看起来像这样:
DATE
Investment
Flow
2012-05-12
1
-50
2013-09-04
1
100
2014-05-05
1
300
2013-09-04
2
-700
2015-05-12
2
1000
2012-04-04
3
100
2013-05-12
3
-50
2013-09-04
4
-60
还有一个像这样
DATE
Investment
Stock
2012-09-05
1
400
2014-05-05
1
600
2014-05-05
2
300
2013-09-04
2
800
2012-09-14
3
1000
2013-09-05
4
6000
所以我想创建多个数据框,其中包含每项投资的流程,直到我获得有关股票的信息为止,最后一行包含该日期的股票。因此,例如,我对投资 1 的股票有 2 个观察结果,因此我应该为投资 1 创建 2 个数据框,如下所示:
DATE
Investment
Flow + Stock(last row)
2012-05-12
1
-50
2012-09-05
1
400
DATE
Investment
Flow + Stock(last row)
2012-05-12
1
-50
2013-09-04
1
100
2014-05-05
1
300
2014-05-05
1
600
对于投资 3,假设我只有一个股票观察,应该只有 1 个如下所示的数据框:
DATE
Investment
Flow + Stock(last row)
2012-04-04
3
100
2012-09-14
3
1000
考虑到我有很多数据,手动创建每个数据框很麻烦,而且我希望这段代码在我有新信息时更新 IRR。我想这样做是因为我想查看每个日期的 IRR 演变,我有每项投资的股票信息。有点像投资内部收益率的时间序列。我将使用创建的数据帧计算 IRR。
我尝试对每项投资的股票信息的日期进行排名,但遇到循环问题。
非常感谢
编辑:
根据 Henry Ecker 的要求,这是合并数据库的示例。
DATE_x Investment Flow DATE_y Stock
355 2018-08-29 1 1371300 2020-09-30 2904678,03
3076 2016-03-31 2 -4535569 2015-06-30 0
1564 2017-11-28 3 1142227 2014-09-30 10378007,31
3666 2018-02-22 2 1622857 2020-03-31 122203846,09
1394 2017-05-16 3 3116642 2017-12-31 0
472 2013-11-09 3 -4364500 2015-12-31 45789217,93
446 2021-02-23 1 325117 2020-03-31 13176648,97
1641 2018-01-31 3 623695 2015-09-30 0
1297 2017-03-21 3 1146193 2015-09-30 32103654,6
2080 2020-09-15 3 461123 2017-09-30 47763628,79
解决此问题的一种方法是加入流和观察以获得关联,然后按观察日期和投资 ID 分组以获得我们感兴趣的每个组。
函数process_df
用于仅过滤掉观察日期(DATE_y
)之前的天数。
从第一行中获取值 Investment、Observation Date (DATE_y
) 和 Stock value,因为它们在组中都是相同的,并将其附加到 table 的末尾。然后清理所有内容,删除额外的列(Stock 和 DATE_y),重置索引,并重命名列以反映您想要的输出。
import pandas as pd
flows = pd.DataFrame({'DATE': {0: '2012-05-12', 1: '2013-09-04',
2: '2014-05-05', 3: '2013-09-04',
4: '2015-05-12', 5: '2012-04-04',
6: '2013-05-12', 7: '2013-09-04',
8: '2020-05-12', 9: '2016-07-12'},
'Investment': {0: 1, 1: 1, 2: 1, 3: 2,
4: 2, 5: 3, 6: 3, 7: 4,
8: 5, 9: 7},
'Flow': {0: -50, 1: 100, 2: 300, 3: -700,
4: 1000, 5: 100, 6: -50, 7: -60,
8: 100, 9: 800}})
flows['DATE'] = flows['DATE'].astype('datetime64[ns]')
observations = pd.DataFrame({'DATE': {0: '2012-09-05', 1: '2014-05-05',
2: '2014-05-05', 3: '2013-09-04',
4: '2012-09-14', 5: '2013-09-05',
6: '2014-05-14', 7: '2015-12-14'},
'Investment': {0: 1, 1: 1, 2: 2,
3: 2, 4: 3, 5: 4,
6: 5, 7: 6},
'Stock': {0: 400, 1: 600, 2: 300,
3: 800, 4: 1000, 5: 6000,
6: 0, 7: 15}})
observations['DATE'] = observations['DATE'].astype('datetime64[ns]')
def process_df(df):
out = df[df['DATE_x'] <= df['DATE_y']] # Filter Out Out of Bound Dates
if out.empty:
# Handle Case Where Observation but No flows
return df[['DATE_y', 'Investment', 'Stock']] \
.reset_index(drop=True) \
.rename(columns={'DATE_y': 'DATE', 'Stock': 'Flow + Stock(last row)'})
return out.drop(['DATE_y', 'Stock'], axis=1) \
.append(out[['Investment', 'DATE_y', 'Stock']]
.iloc[0]
.rename({'DATE_y': 'DATE_x', 'Stock': 'Flow'})) \
.reset_index(drop=True) \
.rename(columns={'DATE_x': 'DATE', 'Flow': 'Flow + Stock(last row)'})
merged = pd.merge(flows, observations, on='Investment', how='right')
dfs = [process_df(group) for _, group in merged.groupby(['Investment', 'DATE_y'])]
# For Display
for i, new_df in enumerate(dfs):
print(f'DataFrame {i+1}')
print(new_df)
print()
dfs 是一个包含各个 DataFrame 的列表。
输出:
DataFrame 1
DATE Investment Flow + Stock(last row)
0 2012-05-12 1 -50.0
1 2012-09-05 1 400.0
DataFrame 2
DATE Investment Flow + Stock(last row)
0 2012-05-12 1 -50.0
1 2013-09-04 1 100.0
2 2014-05-05 1 300.0
3 2014-05-05 1 600.0
DataFrame 3
DATE Investment Flow + Stock(last row)
0 2013-09-04 2 -700.0
1 2013-09-04 2 800.0
DataFrame 4
DATE Investment Flow + Stock(last row)
0 2013-09-04 2 -700.0
1 2014-05-05 2 300.0
DataFrame 5
DATE Investment Flow + Stock(last row)
0 2012-04-04 3 100.0
1 2012-09-14 3 1000.0
DataFrame 6
DATE Investment Flow + Stock(last row)
0 2013-09-04 4 -60.0
1 2013-09-05 4 6000.0
DataFrame 7
DATE Investment Flow + Stock(last row)
0 2014-05-14 5 0
DataFrame 8
DATE Investment Flow + Stock(last row)
0 2015-12-14 6 15
编辑笔记:
- 我最初的实现做出了一个错误的假设,即所有观察结果都至少有一个流。我猜测您希望如何接收没有流量关联的观察信息,并选择 return 一个 DataFrame,它的最后一行仍然包含库存信息但没有流量。如果您更喜欢空的 DataFrame,请直接 return out。
if out.empty:
# Handle Case Where Observation but No flows
return out
- 我在示例数据中添加了 3 个额外的测试用例。
- 有流量,但发生在观察之后
- 给定投资 ID 没有流量
- 有流量没有观察。
- 鉴于您生成的数据帧是基于观察结果的,我选择使用 'right' 连接排除在观察结果中不匹配的流。
我需要帮助计算不同投资的内部收益率,以及这些投资在不同时间的内部收益率。
所以有一个数据框看起来像这样:
DATE | Investment | Flow |
---|---|---|
2012-05-12 | 1 | -50 |
2013-09-04 | 1 | 100 |
2014-05-05 | 1 | 300 |
2013-09-04 | 2 | -700 |
2015-05-12 | 2 | 1000 |
2012-04-04 | 3 | 100 |
2013-05-12 | 3 | -50 |
2013-09-04 | 4 | -60 |
还有一个像这样
DATE | Investment | Stock |
---|---|---|
2012-09-05 | 1 | 400 |
2014-05-05 | 1 | 600 |
2014-05-05 | 2 | 300 |
2013-09-04 | 2 | 800 |
2012-09-14 | 3 | 1000 |
2013-09-05 | 4 | 6000 |
所以我想创建多个数据框,其中包含每项投资的流程,直到我获得有关股票的信息为止,最后一行包含该日期的股票。因此,例如,我对投资 1 的股票有 2 个观察结果,因此我应该为投资 1 创建 2 个数据框,如下所示:
DATE | Investment | Flow + Stock(last row) |
---|---|---|
2012-05-12 | 1 | -50 |
2012-09-05 | 1 | 400 |
DATE | Investment | Flow + Stock(last row) |
---|---|---|
2012-05-12 | 1 | -50 |
2013-09-04 | 1 | 100 |
2014-05-05 | 1 | 300 |
2014-05-05 | 1 | 600 |
对于投资 3,假设我只有一个股票观察,应该只有 1 个如下所示的数据框:
DATE | Investment | Flow + Stock(last row) |
---|---|---|
2012-04-04 | 3 | 100 |
2012-09-14 | 3 | 1000 |
考虑到我有很多数据,手动创建每个数据框很麻烦,而且我希望这段代码在我有新信息时更新 IRR。我想这样做是因为我想查看每个日期的 IRR 演变,我有每项投资的股票信息。有点像投资内部收益率的时间序列。我将使用创建的数据帧计算 IRR。
我尝试对每项投资的股票信息的日期进行排名,但遇到循环问题。
非常感谢
编辑: 根据 Henry Ecker 的要求,这是合并数据库的示例。
DATE_x Investment Flow DATE_y Stock
355 2018-08-29 1 1371300 2020-09-30 2904678,03
3076 2016-03-31 2 -4535569 2015-06-30 0
1564 2017-11-28 3 1142227 2014-09-30 10378007,31
3666 2018-02-22 2 1622857 2020-03-31 122203846,09
1394 2017-05-16 3 3116642 2017-12-31 0
472 2013-11-09 3 -4364500 2015-12-31 45789217,93
446 2021-02-23 1 325117 2020-03-31 13176648,97
1641 2018-01-31 3 623695 2015-09-30 0
1297 2017-03-21 3 1146193 2015-09-30 32103654,6
2080 2020-09-15 3 461123 2017-09-30 47763628,79
解决此问题的一种方法是加入流和观察以获得关联,然后按观察日期和投资 ID 分组以获得我们感兴趣的每个组。
函数process_df
用于仅过滤掉观察日期(DATE_y
)之前的天数。
从第一行中获取值 Investment、Observation Date (DATE_y
) 和 Stock value,因为它们在组中都是相同的,并将其附加到 table 的末尾。然后清理所有内容,删除额外的列(Stock 和 DATE_y),重置索引,并重命名列以反映您想要的输出。
import pandas as pd
flows = pd.DataFrame({'DATE': {0: '2012-05-12', 1: '2013-09-04',
2: '2014-05-05', 3: '2013-09-04',
4: '2015-05-12', 5: '2012-04-04',
6: '2013-05-12', 7: '2013-09-04',
8: '2020-05-12', 9: '2016-07-12'},
'Investment': {0: 1, 1: 1, 2: 1, 3: 2,
4: 2, 5: 3, 6: 3, 7: 4,
8: 5, 9: 7},
'Flow': {0: -50, 1: 100, 2: 300, 3: -700,
4: 1000, 5: 100, 6: -50, 7: -60,
8: 100, 9: 800}})
flows['DATE'] = flows['DATE'].astype('datetime64[ns]')
observations = pd.DataFrame({'DATE': {0: '2012-09-05', 1: '2014-05-05',
2: '2014-05-05', 3: '2013-09-04',
4: '2012-09-14', 5: '2013-09-05',
6: '2014-05-14', 7: '2015-12-14'},
'Investment': {0: 1, 1: 1, 2: 2,
3: 2, 4: 3, 5: 4,
6: 5, 7: 6},
'Stock': {0: 400, 1: 600, 2: 300,
3: 800, 4: 1000, 5: 6000,
6: 0, 7: 15}})
observations['DATE'] = observations['DATE'].astype('datetime64[ns]')
def process_df(df):
out = df[df['DATE_x'] <= df['DATE_y']] # Filter Out Out of Bound Dates
if out.empty:
# Handle Case Where Observation but No flows
return df[['DATE_y', 'Investment', 'Stock']] \
.reset_index(drop=True) \
.rename(columns={'DATE_y': 'DATE', 'Stock': 'Flow + Stock(last row)'})
return out.drop(['DATE_y', 'Stock'], axis=1) \
.append(out[['Investment', 'DATE_y', 'Stock']]
.iloc[0]
.rename({'DATE_y': 'DATE_x', 'Stock': 'Flow'})) \
.reset_index(drop=True) \
.rename(columns={'DATE_x': 'DATE', 'Flow': 'Flow + Stock(last row)'})
merged = pd.merge(flows, observations, on='Investment', how='right')
dfs = [process_df(group) for _, group in merged.groupby(['Investment', 'DATE_y'])]
# For Display
for i, new_df in enumerate(dfs):
print(f'DataFrame {i+1}')
print(new_df)
print()
dfs 是一个包含各个 DataFrame 的列表。
输出:
DataFrame 1
DATE Investment Flow + Stock(last row)
0 2012-05-12 1 -50.0
1 2012-09-05 1 400.0
DataFrame 2
DATE Investment Flow + Stock(last row)
0 2012-05-12 1 -50.0
1 2013-09-04 1 100.0
2 2014-05-05 1 300.0
3 2014-05-05 1 600.0
DataFrame 3
DATE Investment Flow + Stock(last row)
0 2013-09-04 2 -700.0
1 2013-09-04 2 800.0
DataFrame 4
DATE Investment Flow + Stock(last row)
0 2013-09-04 2 -700.0
1 2014-05-05 2 300.0
DataFrame 5
DATE Investment Flow + Stock(last row)
0 2012-04-04 3 100.0
1 2012-09-14 3 1000.0
DataFrame 6
DATE Investment Flow + Stock(last row)
0 2013-09-04 4 -60.0
1 2013-09-05 4 6000.0
DataFrame 7
DATE Investment Flow + Stock(last row)
0 2014-05-14 5 0
DataFrame 8
DATE Investment Flow + Stock(last row)
0 2015-12-14 6 15
编辑笔记:
- 我最初的实现做出了一个错误的假设,即所有观察结果都至少有一个流。我猜测您希望如何接收没有流量关联的观察信息,并选择 return 一个 DataFrame,它的最后一行仍然包含库存信息但没有流量。如果您更喜欢空的 DataFrame,请直接 return out。
if out.empty:
# Handle Case Where Observation but No flows
return out
- 我在示例数据中添加了 3 个额外的测试用例。
- 有流量,但发生在观察之后
- 给定投资 ID 没有流量
- 有流量没有观察。
- 鉴于您生成的数据帧是基于观察结果的,我选择使用 'right' 连接排除在观察结果中不匹配的流。