OptunaでProphetのパラメータを自動でチューニングする
Optuna
pip install Optuna
サンプル
import os
import yfinance as yf
import pandas as pd
from prophet import Prophet
import matplotlib.pyplot as plt
import optuna
import numpy as np
from sklearn.metrics import mean_squared_error
# 定義
ticker = "NVDA"
file_path = f"{ticker}_stock_data.csv"
def load_and_prepare_data(file_path, ticker):
# データの取得または読み込み
if os.path.exists(file_path):
try:
df = pd.read_csv(file_path)
df['ds'] = pd.to_datetime(df['ds'])
df['y'] = pd.to_numeric(df['y'], errors='coerce')
except ValueError as e:
print(f"Error loading CSV file: {e}")
return fetch_and_save_data(file_path, ticker)
else:
df = fetch_and_save_data(file_path, ticker)
# 欠損値の確認と処理
df.dropna(inplace=True)
return df
def fetch_and_save_data(file_path, ticker):
# 株価データの取得
stock_data = yf.download(ticker, start="2023-01-01", end="2025-01-01")
# 株価データフレームの作成
df = stock_data[['Adj Close']].rename(columns={'Adj Close': 'y'}).reset_index()
df['ds'] = df['Date']
df = df.drop(columns=['Date'])
# データをCSVファイルに保存
df.to_csv(file_path, index=False)
# 保存後に再読み込み
df = pd.read_csv(file_path)
df['ds'] = pd.to_datetime(df['ds'])
df['y'] = pd.to_numeric(df['y'], errors='coerce')
return df
# データのロードと準備
df = load_and_prepare_data(file_path, ticker)
# データ型の確認
print(df.dtypes)
# 目的関数の設定
def objective(trial):
params = {
'changepoint_prior_scale' : trial.suggest_uniform('changepoint_prior_scale', 0.001, 0.5),
'seasonality_prior_scale' : trial.suggest_uniform('seasonality_prior_scale', 0.01, 10),
'seasonality_mode' : trial.suggest_categorical('seasonality_mode', ['additive', 'multiplicative']),
'changepoint_range' : trial.suggest_discrete_uniform('changepoint_range', 0.8, 0.95, 0.001),
'n_changepoints' : trial.suggest_int('n_changepoints', 20, 35),
'interval_width' : trial.suggest_uniform('interval_width', 0.5, 0.8)
}
m = Prophet(**params)
m.fit(df)
df_future = m.make_future_dataframe(periods=365, freq='D')
df_future = df_future[df_future['ds'].dt.weekday < 5] # 土日の予測を除外
df_pred = m.predict(df_future)
# 現在の df['y'] の長さと一致するように予測結果を調整
preds = df_pred.iloc[:len(df['y'])]
val_rmse = np.sqrt(mean_squared_error(df['y'], preds['yhat'].values))
return val_rmse
# ハイパーパラメータの探索の実施
study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=100)
# 最適パラメータの出力
print(f"The best parameters are : \n {study.best_params}")
# 最適パラメータを使用してProphetモデルを作成
best_params = study.best_params
model = Prophet(**best_params)
model.fit(df)
# 未来のデータフレームを作成して予測
future = model.make_future_dataframe(periods=365, freq='D')
future = future[future['ds'].dt.weekday < 5] # 土日の予測を除外
forecast = model.predict(future)
# 予測結果と信頼区間の下限を正の値に調整
forecast['yhat'] = forecast['yhat'].apply(lambda x: max(1, x))
forecast['yhat_lower'] = forecast['yhat_lower'].apply(lambda x: max(1, x))
# 予測結果の可視化
model.plot(forecast)
plt.show()
# 成分のプロット(トレンドのグラフも含む)
model.plot_components(forecast)
plt.show()
説明
- インポートと定義
import os
import yfinance as yf
import pandas as pd
from prophet import Prophet
import matplotlib.pyplot as plt
import optuna
import numpy as np
from sklearn.metrics import mean_squared_error
ticker = "NVDA"
file_path = f"{ticker}_stock_data.csv"
ここでは、必要なライブラリをインポートし、株式ティッカー(ここではNVIDIA)とデータの保存先ファイルパスを定義しています。
- データのロードと準備
def load_and_prepare_data(file_path, ticker):
if os.path.exists(file_path):
try:
df = pd.read_csv(file_path)
df['ds'] = pd.to_datetime(df['ds'])
df['y'] = pd.to_numeric(df['y'], errors='coerce')
except ValueError as e:
print(f"Error loading CSV file: {e}")
return fetch_and_save_data(file_path, ticker)
else:
df = fetch_and_save_data(file_path, ticker)
df.dropna(inplace=True)
return df
この関数は、指定されたファイルパスからデータを読み込むか、新しいデータを取得して保存します。データに欠損値がないか確認し、適切に処理します。
- データの取得と保存
def fetch_and_save_data(file_path, ticker):
stock_data = yf.download(ticker, start="2023-01-01", end="2025-01-01")
df = stock_data[['Adj Close']].rename(columns={'Adj Close': 'y'}).reset_index()
df['ds'] = df['Date']
df = df.drop(columns=['Date'])
df.to_csv(file_path, index=False)
df = pd.read_csv(file_path)
df['ds'] = pd.to_datetime(df['ds'])
df['y'] = pd.to_numeric(df['y'], errors='coerce')
return df
ここでは、yfinanceを使ってNVIDIAの株価データを取得し、適切な形式に整形してCSVファイルに保存します。その後、再度CSVファイルからデータを読み込みます。
- データのロードと型の確認
df = load_and_prepare_data(file_path, ticker)
print(df.dtypes)
データをロードし、データ型を確認します。
- 目的関数の設定とハイパーパラメータの最適化
def objective(trial):
params = {
'changepoint_prior_scale': trial.suggest_uniform('changepoint_prior_scale', 0.001, 0.5),
'seasonality_prior_scale': trial.suggest_uniform('seasonality_prior_scale', 0.01, 10),
'seasonality_mode': trial.suggest_categorical('seasonality_mode', ['additive', 'multiplicative']),
'changepoint_range': trial.suggest_discrete_uniform('changepoint_range', 0.8, 0.95, 0.001),
'n_changepoints': trial.suggest_int('n_changepoints', 20, 35),
'interval_width': trial.suggest_uniform('interval_width', 0.5, 0.8)
}
m = Prophet(**params)
m.fit(df)
df_future = m.make_future_dataframe(periods=365, freq='D')
df_future = df_future[df_future['ds'].dt.weekday < 5]
df_pred = m.predict(df_future)
preds = df_pred.iloc[:len(df['y'])]
val_rmse = np.sqrt(mean_squared_error(df['y'], preds['yhat'].values))
return val_rmse
Optunaを使ってハイパーパラメータの最適化を行います。目的関数では、Prophetモデルを作成し、データにフィットさせて予測を行い、予測誤差を計算します。
- ハイパーパラメータの最適化
study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=100)
print(f"The best parameters are : \n {study.best_params}")
Optunaを使って目的関数を最適化し、最適なハイパーパラメータを見つけます。
- モデルの作成と予測
best_params = study.best_params
model = Prophet(**best_params)
model.fit(df)
future = model.make_future_dataframe(periods=365, freq='D')
future = future[future['ds'].dt.weekday < 5]
forecast = model.predict(future)
forecast['yhat'] = forecast['yhat'].apply(lambda x: max(1, x))
forecast['yhat_lower'] = forecast['yhat_lower'].apply(lambda x: max(1, x))
最適なハイパーパラメータを使ってProphetモデルを作成し、将来の予測を行います。予測値と信頼区間の下限を正の値に調整します。
- 予測結果の可視化
model.plot(forecast)
plt.show()
model.plot_components(forecast)
plt.show()
予測結果と成分(トレンドや季節性)のプロットを作成し、可視化します。
ディスカッション
コメント一覧
まだ、コメントがありません