はじめに
商品の販売データセットを用いて、Prophetを使った時系列分析手法で、今後の商品の販売数を予測する。
解決したい社会課題
店舗における過去の商品の販売データが存在するが、これらのデータを上手く利用できない場合が多い。
これらのデータから、売れ筋商品などの商品在庫を適切なタイミングで適切な量だけ持つことができるようにすれば、商品の売れ残りの発生による商品の廃棄を防ぎ、このようなリスクを低減できる。
すなわち、効率的な経営を目指すことができる。
分析するデータ
Kaggleの「店舗商品の需要予測における課題 Store Item Demand Forecasting Challenge」のデータセットを用いて分析結果をまとめる。
実行環境
パソコン:Windows11
開発環境:Google Coraboratory
言語:Python
ライブラリ:Pandas、Numpy、Matplotlib
分析の流れ
- 課題把握とゴールの設定
- 必要なライブラリのインポート
- データの準備
- 予測モデルの学習
- 予測
- 予測の評価
- 設定したゴールの回答
分析の過程
1. 課題把握とゴールの設定
異なる店舗における向こう2年の商品の売上数を予測する。
2. 必要な必要なライブラリのインポート
# 必要なライブラリをインポート
import pandas as pd
import seaborn as sns
3. データの準備
データセットの説明
ファイルの説明
Kaggleの店舗商品の需要予測における課題 https://www.kaggle.com/competitions/demand-forecasting-kernels-only/overview で公開されているデータが比較的シンプルで分かりやすいため、このデータセットを用いる。
train.csv : トレーニングデータ
データを取り込む
Kaggle でこのコンペに参加して、train.csv をダウンロードしてデータを取り込む。
# データを取り込む
train = pd.read_csv('/content/drive/MyDrive/demand-forecasting-kernels-only/train.csv')
train.info()
| Column | 概要 |
|---|---|
| date | 販売データの日付(祝日や店舗休業の影響はありません) |
| store | ストアID |
| item | アイテムID |
| sales | 特定の店舗で特定の日付に販売された商品の数 |
dateカラムを日付データに変換する
# 日付データを指定(train)
train["date"] = pd.to_datetime(train["date"])
train["date"]
train["date"].info()
1系列だけで動かす
データセットには10店舗 × 50商品の日次売上のデータがある。
Prophetはまず「1系列ずつ」試すのが理解しやすいので、今回は 1店舗×1商品 から始める。
# 1店舗×1商品だけ取り出す
store_id = 1
item_id = 1
# 1店舗を取り出す
train[(train["store"] == store_id)]
# 1商品を取り出す
train[(train["item"] == item_id)]
# 1店舗×1商品を取り出す
ts = train[(train["store"] == store_id) & (train["item"] == item_id)]
ts
Prophet用の列名に変更
Prophetでは、学習用データを ds 列=日付、y 列=目的変数 にして渡す。
df = ts.rename(columns={'date': 'ds', 'sales': 'y'})
df
df = df[['ds', 'y']]
df
前処理
上記データフレーム(df)から商品の販売数を折れ線グラフで描画する。
# 折れ線グラフの描画
time = pd.to_datetime(df['ds'])
sns.lineplot(x=time, y=df['y'])

緩やかですが、商品の販売個数が年々増加していて、一定の周期的な変動も確認できた。
夏ごろの販売数が多く、冬頃の販売数が少ない様子がみられた。目立った外れ値は無いと判断する。
欠損値が無いか確認する。
df.info()

ds、yのカラムにnon-nullと表示され、1826個の値を持ち、欠損がないことが確認できた。前処理として欠損の対応も不要と判断する。
データフレームの要約統計量(データの全体像を把握するための数値)を表示する。
df.describe()
4. 予測モデルの学習
Prophetを使用して予測モデルの学習を行う。
# Prophetクラスをインポートしてインスタンス化する
from prophet import Prophet
model = Prophet()
# fitメソッドで学習
model.fit(df)
5. 予測
学習済み予測モデルを利用して予測を行う。
予測の事前準備として、予測したい未来日時を含むDataFrameを作成する。
1か月間隔・毎月初日・向こう2年という枠組みで予測する。
| Alias | 日時データの間隔 |
|---|---|
| D | 1日 |
| M | 1か月(追加される日時データは、月の最終日となる) |
| MS | 1か月(追加される日時データは、月の初日となる) |
| H | 1時間 |
# 1か月間隔・毎月初日・向こう2年(730日)の枠組みで予測
future = model.make_future_dataframe(periods=730, freq='D')
future

2018-01-01から2019-12-31の2年間の日付情報が生成された。
商品の販売個数予測を行う。
forecast = model.predict(future)
forecast

不確実性区間の範囲内に、実際の商品の販売個数の値がどの程度含まれているかの割合を推定する。
| 列名 | 概要 |
|---|---|
| ds | 日付 |
| yhat | 旅客数の予測値 |
| yhat_lower | 予測値の不確実性区間の下限 |
| yhat_upper | 予測値の不確実性区間の上限 |
# 日付、旅客数の予測値、不確実性区間を表示
forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']]

これらの日付、商品の販売数、不確実性区間の値をグラフ上に可視化する。
# これらの値をグラフ上に可視化
fig_forecast = model.plot(forecast)

向こう2年(2018-01-01から2019-12-31)の予測が追加された。
黒点が商品の販売個数の実際の値、青ラインが予測モデルによる商品の販売個数の予測値、水色のエリアが予測値の不確実性区間である。
6. 予測の評価
テストパターンを作成する
過去のデータを使って、複数パターンのテストを実施する。テストパターンは、cutoffsとhorizonという2つのパラメータで調整できる。
| パラメータ | 概要 |
|---|---|
| cutoffs | いつまでのデータを学習データとするかという期限の日付 |
| horizon | cutoffs翌日以降のテスト期間 |
テストデータ期限(cutoffs)を2014/12/31, 2015/12/31, 2016/12/31、学習期間(horizon)を1年(365日)とする。
テストデータ期限として3つの日付要素(cutoffs)と、学習期間として1年(365日)(horizon)を指定する。
from prophet.diagnostics import cross_validation
# cutoffsを2014/12/31, 2015/12/31, 2016/12/31
cutoffs = pd.to_datetime(['2014-12-31', '2015-12-31', '2016-12-31'])
# テストパターンを作成する
df_cv = cross_validation(model, horizon = '365 days', cutoffs=cutoffs)
df_cv

1年(365日)× 3 = 1095日分のデータが格納されることを確認できた。
評価指標の算出を実行する
# 評価指標を算出する
df_p = performance_metrics(df_cv)
df_p.head()

monthlyパラメータにTrueを指定して、horizon列を月単位で表示する
# 評価指標を月単位で算出する
df_p = performance_metrics(df_cv, monthly=True)
df_p.head()

行ごとに、さまざまな評価指標が算出されている。それぞれの列名が意味する評価指標は、以下のとおり。
| 列名 | 評価指標 | 英語表記 |
|---|---|---|
| mse | 平均二乗誤差 | Mean squared error |
| rmse | 二乗平均平方根誤差 | Root mean squared error |
| mae | 平均絶対誤差 | Mean absolute error |
| mape | 平均絶対パーセント誤差 | Mean absolute percent error |
| mdape | メディアン絶対パーセント誤差 | Median absolute percent error |
| smape | 対称平均絶対パーセント誤差 | Symmetric mean absolute percentage error |
| coverage | 不確実性区間に予測値が含まれている割合 | Coverage |
二乗平均平方根誤差(rmse)の推移を可視化
実際の値と予測値の二乗平均平方根誤差(rmse)の推移を可視化する。
# [二乗平均平方根誤差]の推移を可視化
sns.lineplot(x='horizon', y='rmse', data=df_p).set(ylim=(3.5, 5.5))

二乗平均平方根誤差は、だいたい5.0程度の誤差になっている。
不確実性区間に予測値が含まれている割合(coverage)の推移を可視化
次に、不確実性区間に予測値が含まれている割合の推移を可視化する。
# [不確実性区間に予測値が含まれている割合]の推移を可視化
sns.lineplot(x='horizon', y='coverage', data=df_p).set(ylim=(0.5, 0.9))

不確実性区間に実際の値が含まれる割合は、だいたい70%程度になっている。
結果
実際の値に比べて、予測の値の誤差が二乗平均平方根誤差がおよそ5程度で、不確実性区間に予測値が含まれている割合は、およそ70%になっている。
分析から得られた情報
課題
時系列分析手法のProphetを使って分析してきた。評価指標としてrmse、coverageをパラメータを変えるなどして、算出してきた。coverageは良い値をの結果を得ることができたが、rmseがより良い改善方法を見つける必要があるという課題が発見できた。
考察
今回のデータセットでは、実際の値の平均値は19.97(最小値4、最大値50)であり、rmse(予測誤差)が5である。実感としては、悪くないモデルだと思うが、もう少し精度の良いモデルを期待したい。
まとめ
分析の結果、商品の販売数には周期的な増減と緩やかな上昇傾向が見られた。
特に季節的に需要が高まる時期には販売数が増加する傾向があるため、適切な在庫量を事前に確保する必要がある。
また、不確実性区間が広い時期では予測誤差が大きくなる可能性があることを考慮した発注も必要になる。
今後は、周期的な需要に伴った発注のタイミングを把握して、適切な在庫量を確保した販売戦略を準備する必要がある。
本分析により、需要予測を活用した在庫最適化によって、商品の売れ残りの発生による商品の廃棄を防ぎ、このようなリスクを低減でき、効率的な経営につなげられる可能性があると考えられる。









