前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我用Facebook开源神器Prophet,预测股市行情基于Python(系列2)

我用Facebook开源神器Prophet,预测股市行情基于Python(系列2)

作者头像
量化投资与机器学习微信公众号
发布2018-11-16 15:14:00
2.2K0
发布2018-11-16 15:14:00
举报

本期作者:Eric Brown

本期编辑:Allen | 崙

系列1:我用Facebook开源神器Prophet,预测时间序列基于Python

数据基于标普500指数:

代码语言:javascript
复制
import pandas as pd
import numpy as np
from fbprophet import Prophet
import matplotlib.pyplot as plt
 
%matplotlib inline
 
plt.rcParams['figure.figsize']=(20,10)
plt.style.use('ggplot')
代码语言:javascript
复制
market_df = pd.read_csv('../examples/SP500.csv', index_col='DATE', parse_dates=True)
df = market_df.reset_index().rename(columns={'DATE':'ds', 'SP500':'y'})
df['y'] = np.log(df['y'])
 
#lets take a look at our data quickly
df.set_index('ds').y.plot()

运行Prophet

代码语言:javascript
复制
model = Prophet()
model.fit(df);
future = model.make_future_dataframe(periods=366)
forecast = model.predict(future)

Prophet已经创建了所需的模型并匹配数据。Prophet在默认情况下为我们创建了变化点并将它们存储在.changepoints中。默认情况下,Prophet在初始数据集的80%中添加了25个变化点。在初始化prophet时,可以使用n_changepoints参数更改点的数量(例如,model= prophet (n_changepoints=30))

代码语言:javascript
复制
model.changepoints
代码语言:javascript
复制
70     2009-03-20
141    2009-07-01
211    2009-10-09
281    2010-01-21
352    2010-05-04
422    2010-08-12
492    2010-11-19
563    2011-03-04
633    2011-06-14
703    2011-09-22
774    2012-01-04
844    2012-04-16
914    2012-07-25
984    2012-11-05
1055   2013-02-19
1125   2013-05-30
1195   2013-09-09
1266   2013-12-18
1336   2014-04-01
1406   2014-07-11
1477   2014-10-21
1547   2015-02-02
1617   2015-05-13
1688   2015-08-24
1758   2015-12-02
Name: ds, dtype: datetime64[ns]

除了查看变化点的日期之外,我们还可以查看添加了变化点的图表:

代码语言:javascript
复制
figure = model.plot(forecast)
for changepoint in model.changepoints:
    plt.axvline(changepoint,ls='--', lw=1)

看看上面图表中可能的变化点,我们可以看到它们与一些高点和低点非常吻合。你还可以使用以下代码查看这个可视化:

代码语言:javascript
复制
deltas = model.params['delta'].mean(0)
fig = plt.figure(facecolor='w')
ax = fig.add_subplot(111)
ax.bar(range(len(deltas)), deltas)
ax.grid(True, which='major', c='gray', ls='-', lw=1, alpha=0.2)
ax.set_ylabel('Rate change')
ax.set_xlabel('Potential changepoint')
fig.tight_layout()

从上面的图表中我们可以看到,有相当多的变化点在10到20之间,它们的幅度非常小,在预测中最容易被忽视。

现在,如果我们知道过去的趋势发生了什么变化,我们可以将这些已知的变化点添加到dataframe中。对于这些数据,注:事实上,低或高并不意味着它是一个真正的变化点或趋势变化,但让我们假设它是。

代码语言:javascript
复制
m = Prophet(changepoints=['2009-03-09', '2010-07-02', '2011-09-26', '2012-03-20', '2010-04-06'])
forecast = m.fit(df).predict(future)
m.plot(forecast)

figure = m.plot(forecast)
for changepoint in m.changepoints:
    plt.axvline(changepoint,ls='--', lw=1)

我们可以看到,通过手动设置我们的变化点与使用自动检测变化点相比,我们对模型进行了巨大的更改。除非你非常确定过去的趋势变化点,最好使用Prophet提供的默认值。

Prophet对趋势变化点的使用是非常棒的,特别是那些信号/数据集在信号的生命周期中有显著的变化。也就是说,除非你能确定你的变化点,否则最好让Prophet自动去完成。

预测市场

还是使用标普500指数:

代码语言:javascript
复制
df = market_df.reset_index().rename(columns={'DATE':'ds', 'SP500':'y'})
df['y'] = np.log(df['y'])

model = Prophet()
model.fit(df);
future = model.make_future_dataframe(periods=365) #forecasting for 1 year from now.
forecast = model.predict(future)

figure=model.plot(forecast)

根据现有的数据,很难看出预测(蓝线)和实际数据(黑点)的关系。让我们看一下过去800个数据点(大约2年)的预测和实际预测,而不看未来的预测:

代码语言:javascript
复制
two_years = forecast.set_index('ds').join(market_df)
two_years = two_years[['SP500', 'yhat', 'yhat_upper', 'yhat_lower' ]].dropna().tail(800)
two_years['yhat']=np.exp(two_years.yhat)
two_years['yhat_upper']=np.exp(two_years.yhat_upper)
two_years['yhat_lower']=np.exp(two_years.yhat_lower)
two_years[['SP500', 'yhat']].plot()

你可以从上面的图表中看到,预测很好地遵循了趋势,但似乎不太擅长捕捉市场的“波动”。如果我们对“顺应趋势”,而不是试图完美地把握高峰和低谷,这对我们来说可能是件好事。

让我们来看看一些测量准确度的方法:

代码语言:javascript
复制
two_years_AE = (two_years.yhat - two_years.SP500)
print two_years_AE.describe()
 
count    800.000000
mean      -0.540173
std       47.568987
min     -141.265774
25%      -29.383549
50%       -1.548716
75%       25.878416
max      168.898459
dtype: float64

再来看看一些更精确的测量方法。使用sklearn的r2_score函数的R-squared:

代码语言:javascript
复制
r2_score(two_years.SP500, two_years.yhat)
0.90563333683064451

R-squared看起来不错,在任何第一轮建模中,都会取0.9。

现在我们来看看均值平方误差:

代码语言:javascript
复制
mean_squared_error(two_years.SP500, two_years.yhat)
2260.2718233576029

现在,让我们看看平均绝对误差(MAE)。能让我们更好地了解错误率,而不是标准平均值。

代码语言:javascript
复制
mean_absolute_error(two_years.SP500, two_years.yhat)
36.179476001483771

MAE还告诉我们,通过Prophet预测交易并不理想。

另一种查看该预测有效性的方法是根据实际值绘制预测的上置信区间和下置信区间。可以通过绘制yhat_upper和yhat_lower来实现。

代码语言:javascript
复制
fig, ax1 = plt.subplots()
ax1.plot(two_years.SP500)
ax1.plot(two_years.yhat)
ax1.plot(two_years.yhat_upper, color='black',  linestyle=':', alpha=0.5)
ax1.plot(two_years.yhat_lower, color='black',  linestyle=':', alpha=0.5)

ax1.set_title('Actual S&P 500 (Orange) vs S&P 500 Forecasted Upper & Lower Confidence (Black)')
ax1.set_ylabel('Price')
ax1.set_xlabel('Date')

你不能从这张图表中看出任何可以量化的东西,但你可以对预测的价值做出判断。如果你想做短线交易(1天到几周),这个预测几乎是无用的,但是如果你的投资时间是几个月到几年,这个预测可能会提供一些价值,以更好地了解市场的趋势和预测的趋势。

让我们回过头来看看实际的预测,看看它是否能告诉我们一些与预测和实际数据不同的东西。

代码语言:javascript
复制
fig, ax1 = plt.subplots()
ax1.plot(full_df.SP500)
ax1.plot(full_df.yhat, color='black', linestyle=':')
ax1.fill_between(full_df.index, np.exp(full_df['yhat_upper']), np.exp(full_df['yhat_lower']), alpha=0.5, color='darkgray')
ax1.set_title('Actual S&P 500 (Orange) vs S&P 500 Forecasted (Black) with Confidence Bands')
ax1.set_ylabel('Price')
ax1.set_xlabel('Date')

L=ax1.legend() 
L.get_texts()[0].set_text('S&P 500 Actual') 
L.get_texts()[1].set_text('S&P 5600 Forecasted')

这个图比默认的Prophet表图容易理解。我们可以看到,在实际价值和预测的历史中,Prophet做了一个不错的预测但是在市场变得非常不稳定的时候,它的表现很一般。

具体看一下未来的预测,Prophe告诉我们市场将继续上升,在预测期结束时应该在2750左右,区间从2000到4000左右。也许我们可以更准确地使用每周或每月的数据预测。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-11-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 量化投资与机器学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 系列1:我用Facebook开源神器Prophet,预测时间序列基于Python
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档