深層学習でピザの売り上げ予測

今回予測の目的は現職で販売をしており、時系列データで予測を行うことにより自店舗の売り上げ予測も出来ると考えまずは練習として自分の好物のピザで売上予測をしてみました。　機械学習の勉強を始めて６ヶ月が経地ましたが実際のデータでモデル構築は経験していなかった為、不安ですがこれまでの経験も活かしつつ、これから機械学習を勉強する人への参考記事にもなったら良いなと思っています。

## 目次

[はじめに](##-はじめに)
[自己紹介](##-自己紹介)
[データの中身](##-データの中身)
[実行環境](##-実行環境)
[データの状態](##-データの状態)
[必要モジュール](##-必要モジュール)
[1.データの読み込み](##-1.データの読み込み)
[２．データの整理](##-２．データの整理)
[orderの最適化関数](##-orderの最適化関数)
[モデルの構築](##-モデルの構築)
[結果](##-結果)
[まとめ](##-まとめ)

## はじめに
初めまして。転職を考えるうちに自分の人生や働き方について深く考えるようになりました。異業種にチャレンジしたいという気持ちが強くなりプログラミングを学ぶことから始めました。初心者ですがどうぞ宜しくお願い致します。

## 自己紹介
１歳半の息子が居るサラリーマンパパです。
progate等でコードを開いてみたりしましたが本格的な勉強は初めてになります。
アイデミーデータ分析講座にてプログラミングを勉強中です
目的
私は雪国新潟の出身で毎年必ず雪が降ります。しかし積雪量というのは毎年異なり、腰の高さまで降る年もあれば、除雪が必要のない位少ない年もあります。最近の積雪量は異常気象により予測が難しいものとなっておりますが、今年の積雪も気になるところではありますので積雪量が予測できるようにしていきたいと思います。

## データの中身
【期間】2015年1月～2015年１２月までのピザの売上枚数

## 実行環境
Google Colaboratory



## データの状態
データはkaggleからダウンロードしました。
<details><summary>info</summary>



```python
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 48620 entries, 0 to 48619
Data columns (total 12 columns):
 #   Column             Non-Null Count  Dtype         
---  ------             --------------  -----         
 0   order_details_id   48620 non-null  int64         
 1   order_id           48620 non-null  int64         
 2   pizza_id           48620 non-null  object        
 3   quantity           48620 non-null  int64         
 4   order_date         48620 non-null  datetime64[ns]
 5   order_time         48620 non-null  object        
 6   unit_price         48620 non-null  float64       
 7   total_price        48620 non-null  float64       
 8   pizza_size         48620 non-null  object        
 9   pizza_category     48620 non-null  object        
 10  pizza_ingredients  48620 non-null  object        
 11  pizza_name         48620 non-null  object        
dtypes: datetime64[ns](1), float64(2), int64(3), object(6)
memory usage: 4.5+ MB
```
</details>

## 必要モジュール
まずは必要なモジュールをimportします。実行環境に以下のコードを書きます。
<details><summary>importコード</summary>



```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
import missingno as msno
```
</details>

## 1.データの読み込み
Excelデータの為、pandasを用いて読み込みます。
<details><summary>コード</summary>



```python
df = pd.read_excel('/content/Data Model - Pizza Sales.xlsx')
```
</details>



## ２．データの整理
まずは欠損している部分を確認します。
<details><summary>コード</summary>



```python
df.isnull().sum()
結果
order_details_id     0
order_id             0
pizza_id             0
quantity             0
order_date           0
order_time           0
unit_price           0
total_price          0
pizza_size           0
pizza_category       0
pizza_ingredients    0
pizza_name           0
dtype: int64
```
</details>
今の所欠損地は見当たりません。とりあえずこのまま進みます。

分かりやすくカラムを'Date'に変換し必要な日付とピザの売上枚数に限定します。
<details><summary>コード</summary>



```python
df = df.rename(columns={'order_date': 'Date'})
df= df[["Date","quantity"]]
```
</details>

一度可視化してみます。
<details><summary>コード</summary>



```python
plt.plot(df["Date"], df["quantity"])
plt.show()
```
</details>
下記の様な結果となりました。

![ダウンロード (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693787/b40b2abf-2a65-0c81-7c89-ace46019aabe.png)

すでにデータの学習を行なっている為、学習データとテストデータで分けたいと思います。
<details><summary>コード</summary>

```python
thresh = int(len(df)*0.9)
train_df = df[:thresh]
test_df = df[thresh:]
```
</details>

ここで欠損している日にちがあった為前日の売上で補う事とします。
<details><summary>コード</summary>

```python
df['Date'] = pd.to_datetime(df['Date'])
df = df.set_index('Date')
#　一日刻みのindexを作成する
index = pd.date_range('2015-01-01	', '2015-12-31', freq='D')
# dummyデータを作成し、dfと結合することで、どこが欠損しているのかを把握する
dummy_df = pd.DataFrame([0]*len(index),index=index,columns=["dummy"])
merge_df = pd.merge(dummy_df, df,left_index=True,right_index=True,how="outer")
print(merge_df[merge_df['quantity'].isnull()==True].index)
#欠損日付一覧['2015-09-24', '2015-09-25', '2015-10-05', '2015-10-12','2015-10-19', '2015-10-26', '2015-12-25']
# 今回は一つ前の値で補うこととする
df = merge_df["quantity"].ffill()
```
</details>

## orderの最適化関数
ここでパラメータを選択するために、時系列データ:DATA, パラメータs(周期):sを入力すると、最も良いパラメーターとそのBICを出力するselectparameteという関数を定義していきます。
<details><summary>コード</summary>

```python
def selectparameter(DATA, s):
    p = d = q = range(0, 2)
    pdq = list(itertools.product(p, d, q))
    seasonal_pdq = [(x[0], x[1], x[2], s) for x in list(itertools.product(p, d, q))]
    parameters = []
    BICs = np.array([])
    for param in pdq:
        for param_seasonal in seasonal_pdq:
            try:
                mod = sm.tsa.statespace.SARIMAX(DATA,
                                                order=param,
                                                seasonal_order=param_seasonal)
                results = mod.fit()
                parameters.append([param, param_seasonal, results.bic])
                BICs = np.append(BICs, results.bic)
            except:
                continue
    return parameters[np.argmin(BICs)]
```
</details>

## モデルの構築
いよいよモデルの構築です。
### 時系列データ解析について
「ピザの売り上げ予測のモデル構築」は、時系列データ解析に該当します。時系列データとは、時間の経過と共に変化するデータのことを指します。時系列データ解析は、会社の売り上げや商品の売り上げの予測にも応用できるので、ビジネスシーンでも非常に重要な分析技術とされています。
### モデルの紹介
今回トレンドと季節性があるデータはSARIMAモデルというモデルで表現することができる為、SARIMAで予測を行いますが、
その他のモデルも紹介します。
#### MAモデル
単に時系列が異なる式との間に共通部分を持つために相関性が存在するという性質を持つモデル

#### ARモデル
過去の値から回帰的にある時点の値を推定するモデル

#### ARMAモデル
ARMAモデル とはその名前の通り後述する ARモデル と MAモデル をあわせたモデルになります。AR(p)のARモデルとMA(q)のMAモデルを組み合わせたときARMA(p,q)のように表すことができます。定常過程にしか適応できません。

#### ARIMAモデル
非定常過程の原系列の差分をとり、ARMAモデルを適応したモデルをARIMAモデルという
先程のARMAモデルへ原系列を階差系列に変換し適応したものをARIMAモデルと言います。非定常過程（データの平均や分散が時間に依存している過程）にも適応可能です。d時点前との差分をとった場合のARMA(p,q)で構築したARIMAモデルをARIMA(p,d,q)と表します。 
pを自己相関度  モデルが直前 p 個の値を用いて予測されるのか を
dを誘導  時系列データを定常にするために d 次の階差が必要だったこと を
qを 移動平均　モデルが直前 q 個の値に影響を受けること を表しています。

#### SARIMAモデル 
ARIMAモデルは(p,d,q)をさらに季節周期を持つ時系列データにも拡張できるようにしたモデルです。SARIMAモデルは(p, d, q)のパラメーターに加えて(sp, sd, sq, s)というパラメーターも持ちます。
sp:季節性自己相関
sd:季節性導出,
sq: 季節性移動平均

上記を踏まえ季節周期を持つ時系列データにも拡張できるようにしたモデルの為、SARIMAで今回は予測していきます。
<details><summary>コード</summary>

```python
# 周期は月ごとのデータであることも考慮してs=12となります
# orderはselectparameter関数の0インデックス, seasonal_orderは1インデックスに格納されています
best_params = selectparameter(train_df, 12)
model = sm.tsa.statespace.SARIMAX(train_df, order=best_params[0],
                                            seasonal_order=best_params[1],
                                            enforce_stationarity=False, enforce_invertibility=False).fit()
```
</details>

## 結果
### 予測と可視化
下記コードで期間を定め可視化します。
<details><summary>コード</summary>

```python
# predに予測期間での予測値を代入
pred = model.predict("2015-11-25", "2015-12-31")

# グラフを可視化。予測値は赤色でプロット。
plt.plot(df)
plt.plot(pred, "r")
plt.show()
```
</details>

### 結果
![ダウンロード (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693787/5d407c16-493d-7e13-f260-5c8bff4ef412.png)

なんとかメンターの方の補助のおかげで予測することが出来ました。
赤色が予測になりますがなんとなく予測はできていると感じました。今回のデータが1年しかない為質の高いデータではないですがうまく予測ができたと思います。

## まとめ
今まで売上の向上する理由など知る余地も無かった為、もっと知りたい。色々なデータで試してみたいと感じました。
今回時系列の予測に関して骨が折れそうになることが難度もあり、メンターの方には質問攻めすることが何度もございました。
自分の将来の為にも今回の講座をより一層理解できる様自分自身で探求し今後に繋げていきたいと思います。
最後までご覧いただきありがとうございました。