ゼロから始める株取引！Python／Prophetで株価予測

# はじめに

過去、いくつかの記事で取り上げた「Pythonで株価トレンド予測[^1][^2][^3]」ですが、、、やはり難しい。
記事で投稿して公開するか迷うレベルの良い方法が見つかることを夢見て、継続しています。

本稿は気分転換として試した、**Prophet**なるPythonライブラリのCodeを紹介してゆきます。

## 本稿で紹介すること

- Prophetとは
- データの収集および整形
- 予測モデルの作成
- 予測結果の確認

## 本稿で紹介しないこと

- Prophetの仕組み
- 予測精度の確認
- 特徴量重要度の確認（可視化）

# Prophetとは

通称**Meta**（メタ、Meta Platforms, Inc.、旧称: Facebook, Inc.）が開発した時系列解析ライブラリ[^4][^5]です。
OSSとして公開されており、PyPIから簡単にインストールできます。
プログラミング言語は、RでもPythonでも利用できます。

以下、本家の紹介文より引用。本稿では、Prophetの仕組みの解説は割愛します。（難しくてお手上げです。）
> Prophet is a procedure for forecasting time series data based on an additive model where non-linear trends are fit with yearly, weekly, and daily seasonality, plus holiday effects. It works best with time series that have strong seasonal effects and several seasons of historical data. Prophet is robust to missing data and shifts in the trend, and typically handles outliers well.
> Prophet is open source software released by Facebook’s Core Data Science team. It is available for download on CRAN and PyPI.


## 環境の準備

過去の投稿記事[^1]と同じ環境に、Prophetを追加インストールしました。

https://qiita.com/Blaster36/items/9bdf777f35fda3335f6a

:::note info
筆者は、作ったコンテナイメージを使ってJupyterHubからコンテナ起動しました。
:::

以下、PythonとPythonライブラリ群のVer情報です。

```shell:
$ python -V
Python 3.8.8
$ python -m pip --version
pip 21.3.1 from /opt/conda/lib/python3.8/site-packages/pip (python 3.8)
```

Prophetのインストールはpipコマンド1行でOKです。

```shell:
!pip install prophet
```

# データの収集および整形

:::note warn
筆者は、自宅PCからプロバイダ網抜けてインターネット接続ありの環境で実行しています。
企業（Proxy環境）の方はお気を付けくださいませ。
:::

過去の投稿記事[^1]に同じ、東証1部の銘柄コードを対象としました。
そのため、以下のPythonコードでデータ取得しています。

```python
start = datetime.date(2018, 1, 1)
end = datetime.date(2022, 1, 1)

df = DataReader('9983.T', 'yahoo', start, end)
```

そして、Prophetの仕様に則り整形します。

https://github.com/facebook/prophet/blob/main/notebooks/quick_start.ipynb

以下、GitHubで公開されたQuickStart[^6]の説明より引用。ざっくり言うと、ds（datestamp）およびy（目的変数）を格納したDataFrameを作ればOKです。
> The input to Prophet is always a dataframe with two columns: ds and y. The ds (datestamp) column should be of a format expected by Pandas, ideally YYYY-MM-DD for a date or YYYY-MM-DD HH:MM:SS for a timestamp. The y column must be numeric, and represents the measurement we wish to forecast.

```python
df['ds'] = df.index
df = df.rename({'Close':'y'}, axis=1)

# 不要カラムの削除と並べ替え
df = df[['ds', 'y']]

# 学習データとテストデータの分割
df_train = df.loc[:'2021-01-01']
df_test = df.loc['2021-01-01':]
```

# 予測モデルの作成

まずは、データを分割します。学習用に３年、テスト用に１年、という割り方です。

```python
# 学習データとテストデータの分割
df_train = df.loc[:'2021-01-01']
df_test = df.loc['2021-01-01':]
```

さまざまなパラメータが設定可能で、適切なパラメータを設定することで精度は変化します。
今回は、こんな感じ（基本デフォルト値）です。
あとは、Scikit-LearnのAPIのように、インスタンス化して、**fit**や**predict**をCallしてゆきます。

```python
params = {'growth': 'linear',
          'changepoints': None,
          'n_changepoints': 25,
          'changepoint_range': 0.8,
          'yearly_seasonality': 'auto',
          'weekly_seasonality': 'auto',
          'daily_seasonality': 'auto',
          'holidays': None,
          'seasonality_mode': 'additive',
          'seasonality_prior_scale': 10.0,
          'holidays_prior_scale': 10.0,
          'changepoint_prior_scale': 0.05,
          'mcmc_samples': 0,
          'interval_width': 0.80,
          'uncertainty_samples': 1000,
          'stan_backend': None
         }

# Prophet 予測モデル構築
df_prophet_model = Prophet(**params)
df_prophet_model.fit(df_train)
```

# 予測結果の確認

学習が完了したら、テスト区間で予測します。
**make_future_dataframe**で学習データの期間に対して、予測したい期間（≒テスト区間）を追加したDataFrameを作成します。

```python
# Prophet 予測モデルの精度検証用データの生成
df_future = df_prophet_model.make_future_dataframe(periods=len(df_test), freq='d')
df_pred = df_prophet_model.predict(df_future)

# Prophet 予測モデルの予測結果（学習データ期間＋テストデータ期間）
df_pred_plot = df_prophet_model.plot(df_pred)         #予測値（黒い点は学習データの実測値）
df_pmpc = df_prophet_model.plot_components(df_pred)   #モデルの要素分解（トレンド、週周期、年周期）
```

可視化すると、以下のようになりました。
グラフ右側、実測値のない期間の青線部分がテスト区間の予測値で、淡い水色の範囲は誤差の範囲です。
今回の予測モデルだと、2021年4月頃に一度落ち込むもその後は跳ね上がり、2021年9月頃ピークに向けて上昇の見込みです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685193/f2ab4963-331c-f9b6-3525-cf0cd93414d0.png)

## 結果の可視化（実測値と予測値）

実測値と予測値のデータを重ねて可視化し、実際の株価値動きを捕捉できていたか否かを確かめてみます。
波形を細かく見るために、大きめに描画しています。

```python
# テストデータに予測値を結合
df_test.loc[:, 'Prophet Predict'] = df_pred['yhat'][-245:].to_list()

plt.figure(figsize=[20, 15])

# 実測データと予測データの折れ線グラフを描画
df_test['y'].plot(title='Forecast evaluation', kind='line')
df_test['Prophet Predict'].plot(title='Forecast evaluation', kind='line')

# グラフの凡例を設定
plt.legend(['y', 'Prophet Predict'])

# x軸の範囲を変更する
#plt.xlim('2021-10-01', '2021-12-31')
# y軸の範囲を変更する
plt.ylim(60000, 140000)

# グラフの表示
plt.show()
```

予測に反し、現実は値下がりしていますね。絶対値は違えども、波形は似ている区間もあるような気もしますが。
株価は外部要因の影響を受けてカオスな値動きになると思ってて、過去の株価だけで未来の株価を予測するのは困難と言われたりもしますし。
コロナ禍というのがまた予測を難しくした要因かもしれず、コロナの世界的流行以前の世界だとまた少し違う結果になるかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685193/df746b32-a8c4-05d4-0b9b-59d32fa1110d.png)


# Notebook（Pythonコード）

githubで公開しました。

https://github.com/Blaster36/Script/blob/main/StockPrice/predStockPrice-Prophet1.ipynb

# まとめ

株価（時系列データ）予測のモデルはやはり難しい、というのが正直な意見です。
が、Prophet自体は高度な知識なくとも手軽に予測モデルを作ることができ、使い勝手は良いかなという印象でした。


[^1]: ゼロから始める株取引！Pythonで株価トレンド予測（１本目：CSVファイルの準備まで） | https://qiita.com/Blaster36/items/9bdf777f35fda3335f6a
[^2]: ゼロから始める株取引！Pythonで株価トレンド予測（２本目：予測モデルの作成から） | https://qiita.com/Blaster36/items/00c1f95f173b63ab3c42
[^3]: ゼロから始める株取引！Pythonで株価トレンド予測（Tips：特徴量重要度を表形式で表示） | https://qiita.com/Blaster36/items/7111f2a83e537b46e187
[^4]: Prophet | https://facebook.github.io/prophet/
[^5]: facebook/prophet | https://github.com/facebook/prophet
[^6]: quick_start.ipynb | https://github.com/facebook/prophet/blob/main/notebooks/quick_start.ipynb