在 30 天的时间内 PANDAS 滚动产品 window
Rolling Product in PANDAS over 30-day time window
我正在尝试为金融事件分析准备数据,并想计算买入并持有的异常值 return (BHAR)。对于测试数据集,我有三个事件(用 event_id 表示),对于每个事件,我有 272 行,从 t-252 天到 t+20 天(由变量 time 记录)。对于每一天,我还有股票的 return 数据 (ret) 以及预期的 return (Exp_Ret),这是使用市场模型计算的。这是数据示例:
index event_id time ret vwretd Exp_Ret
0 0 -252 0.02905 0.02498 nan
1 0 -251 0.01146 -0.00191 nan
2 0 -250 0.01553 0.00562 nan
...
250 0 -2 -0.00378 0.00028 -0.00027
251 0 -1 0.01329 0.00426 0.00479
252 0 0 -0.01723 -0.00875 -0.01173
271 0 19 0.01335 0.01150 0.01398
272 0 20 0.00722 -0.00579 -0.00797
273 1 -252 0.01687 0.00928 nan
274 1 -251 -0.00615 -0.01103 nan
这就是问题所在。我想每天计算以下 BHAR 公式:
所以,以上面的公式为例,如果我想计算10天的买入并持有异常值return,我必须计算(1+ret_t =0)x(1+ret_t=1)...x(1+ret_t=10), 然后对预期的 return, (1+Exp_Ret_t=0)x(1+Exp_Ret_t=1)...x(1+Exp_Ret_t=10), 然后前者减去后者.
我使用 rolling_apply 取得了一些进步,但它并没有解决我所有的问题:
df['part1'] = pd.rolling_apply(df['ret'], 10, lambda x : (1+x).prod())
这似乎正确地实现了 BHAR 方程的左侧,因为它将添加正确的乘积——尽管它将输入向下两行的值(这可以通过移动来解决)。但是,一个问题是数据框中存在三个不同的 'groups'(3 个事件),如果 window 向前推进超过 30 天,它可能会开始使用下一个事件的产品。我试图用 rolling_apply 实现 groupby 但不断出现错误: TypeError: 'Series'对象是可变的,因此它们不能被散列
df.groupby('event_id').apply(pd.rolling_apply(df['ret'], 10, lambda x : (1+x).prod()))
我确信我在这里遗漏了一些基本的东西,因此我们将不胜感激。我可能只需要从不同的角度来处理它。这是一个想法:最后,我最感兴趣的是从 time=0 开始获取 30 天和 60 天买入并持有异常 returns。所以,也许更容易 select 每个时间为 0 的事件,然后计算未来 30 天的产品?我不确定如何才能最好地解决这个问题。
提前感谢您的任何见解。
编辑后 BHAR 的最终值包含在主 DataFrame 中。
BHAR = pd.Series()
def bhar(arr):
return np.cumprod(arr+1)[-1]
grouped = df.groupby('event_id')
for name, group in grouped:
BHAR = BHAR.append(pd.rolling_apply(group['ret'],10,bhar) -
pd.rolling_apply(group['Exp_Ret'],10,bhar))
df['BHAR'] = BHAR
然后您可以使用 df[df['time']>=0]
对 DataFrame 进行切片,以便您只获得所需的部分。
您显然可以在组中使用 .apply()
将循环折叠成一行,但我喜欢这种方式。更短的阅读行 = 更好的可读性。
# Create sample data.
np.random.seed(0)
VOL = .3
df = pd.DataFrame({'event_id': [0] * 273 + [1] * 273 + [2] * 273,
'time': range(-252, 21) * 3,
'ret': np.random.randn(273 * 3) * VOL / 252 ** .5,
'Exp_Ret': np.random.randn(273 * 3) * VOL / 252 ** .5})
# Pivot on time and event_id.
df = df.set_index(['time', 'event_id']).unstack('event_id')
# Calculated return difference from t=0.
df_diff = df.ix[df.index >= 0, 'ret'] - df.loc[df.index >= 0, 'Exp_Ret']
# Calculate cumulative abnormal returns.
cum_returns = (1 + df_diff).cumprod() - 1
# Get 10 day abnormal returns.
>>> cum_returns.loc[10]
event_id
0 -0.014167
1 -0.172599
2 -0.032647
Name: 10, dtype: float64
这是我所做的:
((df+1.0) \
.apply(lambda x: np.log(x),axis=1)\
.rolling(365).sum() \
.apply(lambda x: np.exp(x),axis=1)-1.0)
结果是滚动产品。
我正在尝试为金融事件分析准备数据,并想计算买入并持有的异常值 return (BHAR)。对于测试数据集,我有三个事件(用 event_id 表示),对于每个事件,我有 272 行,从 t-252 天到 t+20 天(由变量 time 记录)。对于每一天,我还有股票的 return 数据 (ret) 以及预期的 return (Exp_Ret),这是使用市场模型计算的。这是数据示例:
index event_id time ret vwretd Exp_Ret
0 0 -252 0.02905 0.02498 nan
1 0 -251 0.01146 -0.00191 nan
2 0 -250 0.01553 0.00562 nan
...
250 0 -2 -0.00378 0.00028 -0.00027
251 0 -1 0.01329 0.00426 0.00479
252 0 0 -0.01723 -0.00875 -0.01173
271 0 19 0.01335 0.01150 0.01398
272 0 20 0.00722 -0.00579 -0.00797
273 1 -252 0.01687 0.00928 nan
274 1 -251 -0.00615 -0.01103 nan
这就是问题所在。我想每天计算以下 BHAR 公式:
所以,以上面的公式为例,如果我想计算10天的买入并持有异常值return,我必须计算(1+ret_t =0)x(1+ret_t=1)...x(1+ret_t=10), 然后对预期的 return, (1+Exp_Ret_t=0)x(1+Exp_Ret_t=1)...x(1+Exp_Ret_t=10), 然后前者减去后者.
我使用 rolling_apply 取得了一些进步,但它并没有解决我所有的问题:
df['part1'] = pd.rolling_apply(df['ret'], 10, lambda x : (1+x).prod())
这似乎正确地实现了 BHAR 方程的左侧,因为它将添加正确的乘积——尽管它将输入向下两行的值(这可以通过移动来解决)。但是,一个问题是数据框中存在三个不同的 'groups'(3 个事件),如果 window 向前推进超过 30 天,它可能会开始使用下一个事件的产品。我试图用 rolling_apply 实现 groupby 但不断出现错误: TypeError: 'Series'对象是可变的,因此它们不能被散列
df.groupby('event_id').apply(pd.rolling_apply(df['ret'], 10, lambda x : (1+x).prod()))
我确信我在这里遗漏了一些基本的东西,因此我们将不胜感激。我可能只需要从不同的角度来处理它。这是一个想法:最后,我最感兴趣的是从 time=0 开始获取 30 天和 60 天买入并持有异常 returns。所以,也许更容易 select 每个时间为 0 的事件,然后计算未来 30 天的产品?我不确定如何才能最好地解决这个问题。
提前感谢您的任何见解。
编辑后 BHAR 的最终值包含在主 DataFrame 中。
BHAR = pd.Series()
def bhar(arr):
return np.cumprod(arr+1)[-1]
grouped = df.groupby('event_id')
for name, group in grouped:
BHAR = BHAR.append(pd.rolling_apply(group['ret'],10,bhar) -
pd.rolling_apply(group['Exp_Ret'],10,bhar))
df['BHAR'] = BHAR
然后您可以使用 df[df['time']>=0]
对 DataFrame 进行切片,以便您只获得所需的部分。
您显然可以在组中使用 .apply()
将循环折叠成一行,但我喜欢这种方式。更短的阅读行 = 更好的可读性。
# Create sample data.
np.random.seed(0)
VOL = .3
df = pd.DataFrame({'event_id': [0] * 273 + [1] * 273 + [2] * 273,
'time': range(-252, 21) * 3,
'ret': np.random.randn(273 * 3) * VOL / 252 ** .5,
'Exp_Ret': np.random.randn(273 * 3) * VOL / 252 ** .5})
# Pivot on time and event_id.
df = df.set_index(['time', 'event_id']).unstack('event_id')
# Calculated return difference from t=0.
df_diff = df.ix[df.index >= 0, 'ret'] - df.loc[df.index >= 0, 'Exp_Ret']
# Calculate cumulative abnormal returns.
cum_returns = (1 + df_diff).cumprod() - 1
# Get 10 day abnormal returns.
>>> cum_returns.loc[10]
event_id
0 -0.014167
1 -0.172599
2 -0.032647
Name: 10, dtype: float64
这是我所做的:
((df+1.0) \
.apply(lambda x: np.log(x),axis=1)\
.rolling(365).sum() \
.apply(lambda x: np.exp(x),axis=1)-1.0)
结果是滚动产品。