SIGNATEで「Jリーグの観客動員数予測」をやってみた。

#1.データ分析について
・予測とはデータに基づき値を想定すること。
・代表的な予測問題は、「回帰」と「分類」。
・予測したいものが数値の場合は「回帰」。
・予測したいものがラベルであれば、0か1かなどは「分類」。
・過学習とはモデル作成に使ったデータだけに特化しすぎたモデル作ると偏ったモデルとなる。
・言い換えると、モデル作成に使ったデータに特化したモデルを作ってしまうと過学習になりやすい。
・汎用的な予測モデルを作るためには、データを全部使うのではなく擬似的に未知のデータを作る。データを分割して「学習データ」と「評価データ」に分類する。
・分割したのちに、学習データだけで作ったモデルについて、評価データだけを使って評価する。これによって未知のデータもちゃんと予測できているかを確認する。
・数値データではなく質的データ（天気など）については、dummy変数化する。


#2.基礎分析について
・データを読み込んでデータを俯瞰する。
・データの詳細を確認する。
・折れ線グラフ、ヒストグラム、箱ひげ図を作成する。
・欠損値を確認する。
・相関関係を調べる。

#3.必要なパッケージをインポート

```.py
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
```
matplotlibの日本語化（インストール後にインポート）

```
pip install japanize-matplotlib
#import japanize_matplotlib
```

＃4.SIGNATEからデータをダウンロードする
・学習用データ（２０１２年〜２０１４年シーズン前半戦（7月31日まで））※観客動員数あり
・評価用データ（２０１４年シーズン後半戦（8月2日〜11月23日まで））※観客動員数なし
・お題：２０１４年後半戦の観客動員数を予測するモデルを作成する。

#5.train,csv、test.csv、sample_submit.csv取得して分析する
ヘッダーがない場合は、header=Noneとする。

```.py
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
sample = pd.read_csv("sample_submit.csv",header=None)
```

###（１）行数と列数を確認したい場合

```
train.shape
```
###（２）基本統計量を確認する
数字のある項目のみであるが基本統計量を確認できる。

```.py
train.describe()
```

###（３）型を調べる

```.py
train.info()
```

###（４）trainデータのyの値の平均を求める

```.py
train["y"].mean()
```
###（５）trainデータのyが10000以上を求める

```.py
train[train["y"]>=10000]
```

###（６）ソートする
trainデータのJ１でかつyを小さい順にソート

```.py
train[train["stage"] == ["Ｊ１"].sort_values(by="y")
```
大きい順にソート

```.py
train[train["stage"] == "Ｊ１"].sort_values(by="y",ascending=False)
```

###（７）trainデータのJ１でかつyの値の平均

```.py
train[train["stage"] == ["Ｊ１"]["y"].mean()
```

###（８）折れ線グラフを書く
サイズは、fisizeを使う。

```.py
train["y"].plot(figsize=(12,4))
```

###（９）折れ線グラフを書いて、x軸、y軸、タイトルをつける
X軸やy軸の名前の付け方は一旦、変数に代入したのちに行う。

```.py
a = train["y"].plot(figsize=(12,4),title="graph")
a.set_xlabel("time")
a.set_ylabel("y")
```

###（１０）ヒストグラム
trainデータのyの値をヒストグラムで書く。

```.py
train["y"].hist()
```

ヒストグラムで平均値を表す。
平均値はaxvlineで引く（色は赤色とする）。

```.py
plt.axvline(x=train["y"].mean(),color="red")
train["y"].hist()
```
ヒストグラムで中央値を表す。
平均値はaxvlineで引く（色は赤色とする）。

```.py
plt.axvline(x=train["y"].median(),color="red")
train["y"].hist()
```
ヒストグラムで最大値を表すして、平均値はaxvlineで引く（色は赤色とする）、png形式で保存する。

```.py
plt.axvline(x=train["y"].max(),color="red")
train["y"].hist()
plt.savefig("sample_fig.png")
```

###（１１）箱ひげ図で書く
例えば、home（ホームのチーム）と、y（動員数）など、**質と数値**の２つの値を比べる時に用いられる。

```.py
train[["y","home"]].boxplot(by="home",figsize=(100,4))
```

###（１１）欠損値を確認する
1つでも欠損値があれば、TRrui、なければFalseとなる

```.py
train.isnull().any()
```
欠損値の数を確認するには、

```.py
train.isnull().sum()
```

欠損値を0で補間する場合は、

```.py
train.fillna(0)
```
ある列の（例えばstadiumに）欠損値を削除するには、

```.py
train.dropna(subset=["stadium"])
```

欠損値は、NaNであるが、例えば - など、確認できないものもある。
例えば、stadiumのカラムに値がそれぞれいくつあるか確認したい場合は、

```.py
train["stadium"].value_counts()
```

###（１２）相関関係を調べる
**数値同士**で相関関係を比べることができる。
例えば、y（観客動員数）と、yearの相関関係は以下の通りとなる。
１に近いければ正の相関が（どちらかが多い時にどちらかも多い）、
−１に近ければ負の相関（どちらかが多い時にどちらかは少ない）、
を意味する。

```.py
train[["y","year"]].corr()
```
**数値同士***で散布図も確認できる。

```.py
train.plot.scatter(x="year",y="y",figsize=(12,5))
```
#6.予測する
scikit-learnをインストールする

```.py
pip install scikit-learn
#from sklearn.linear_model import  LinearRegression as LR
```

（１）ダミー変数化する
目的変数はy（観客動員数）であるが、説明変数について、観客動員数はtrainのstage（J１か、J2か）、またはhomeがどこのチームか、が大きな影響を与えていると仮説を立てる。
ただ、stage、homeともに質的変数のため、ダミー変数化する。
pd.get_dummiesは、自動的にダミー変数化できるかどうかを判別し、ダミー変数化できるものはダミー変数化してくれる。（量的変数を入れても可能）
上記のダミー変数化して、trainXに入れる。

```.py
trainX = pd.get_dummies(train[["stage","home","away"]])
```
（２）回帰モデルの箱を用意する

```.py
model = LR()
```

（３）重回帰モデルを作る

```.py
model.fit(trainX,y)
```


testもダミー変数化する

```.py
testX = pd.get_dummies(test[["stage","home","away"]])
```

testXの予測結果を出す

```.py
pred = model.predict(testX)
```

ところが、以下のようなエラーが出て、実行できない
trainXの列が88に対して、testXの列が82のため列が合致していないためエラーを出した。

```
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 88 is different from 82)
```

#7.エラーを確認する（その①）

いったん、ダミー変数化したtrainXと、testXをcsvに吐き出し検証した。
以下のようにhenkan.pyを作成した。

```.py
trainX.to_csv("trainX_kensyo.csv")
testX.to_csv("testX_kensyo.csv")
```

その後、trainXと、testXの違いを以下のコードで確認する。

```.py:henkan.py
list_train = []
list_test = []


with open("trainX_kensyo.csv",encoding="utf-8")as f:
    for i in f:
        list_train = i.split(',')

with open("testX_kensyo.csv",encoding="utf-8")as f:
    for i in f:
        list_test = i.split(',')

#trainXとtestXの項目の差異が何かを確認して、差異をerror.csvに吐き出す
for i in list_train:
    if i in list_test:
        print("合致")
    else:
        with open("error.csv","a",encoding="utf-8")as f:
            f.write(i)
```
error.csvを確認すると、home,awayの列それぞれの、ガイナーレ鳥取、ザスパ草津、ＦＣ町田ゼルビアの合計６つの列について、testXよりtrainXの方が多いことがわかった。

```.csv:error.csv
home_ガイナーレ鳥取,home_ザスパ草津,home_ＦＣ町田ゼルビア,away_ガイナーレ鳥取,away_ザスパ草津,away_ＦＣ町田ゼルビア,
```

そこで、元データのtrainから、ガイナーレ鳥取、ザスパ草津、ＦＣ町田ゼルビアが含まれる行を削除し、trainXとtestXの列を合わせた上で、train2として保存。

```.py
import re
list_main = []

with open("train.csv",encoding="utf-8")as f:
    for i in f:
        list_main.append(i)

k=0
for i in list_main:
    if re.search("ガイナーレ鳥取",i):
        del list_main[k]
    k+=1

k=0
for i in list_main:
    if re.search("ザスパ草津",i):
        del list_main[k]
    k+=1

k=0
for i in list_main:
    if re.search("ＦＣ町田ゼルビア",i):
        del list_main[k]
    k+=1

for i in list_main:
    with open("train2.csv","a",encoding="utf-8")as f:
        f.write(i)
```

あらためて、train2を読み込み、testXの予測結果を出す

```.py
pred = model.predict(testX)
```

やはりエラーが出る。trainXの列が83に対してtestXの列が82とまだ一致しない。

```
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 83 is different from 82)
```

#8.エラーを確認する（その②）

あらためて、train2を確認する
以下のように、train2で、away列のうち、”ガイナーレ鳥取”に該当する行を抽出する。
pandasの列や行の抽出は以下を参考にした。

```
train[train["away"]=="ガイナーレ鳥取"]
とすると、以下の通り１件該当するためこれを削除してtrain2を保存。
idを指定して削除。
```
id                    14411
y                      3827
year                   2012
stage                    Ｊ２
match               第１１節第１日
gameday          04/30(月・休)
time                  13:03
home                   栃木ＳＣ
stadium        栃木県グリーンスタジアム
tv         スカパー／ｅ２（録）／スカパー光
Name: ガイナーレ鳥取, dtype: object
```

あらためて、train2を読み込み、testXの予測結果を出す

```.py
pred = model.predict(testX)
pred
```
今度は、正常に予測結果が出たため、sampleファイルに代入して、csvに吐き出して、signateに投稿する。

```
sample[1] = pred
sample.to_csv("submit_new.csv",index=None,header=None)
```

結果は、1928人中、687位であった。
低い（泣）

#9.追加データ（train_add）追加する
train2にtrain_addを追加してtrain3をつくる。

```
train_add = pd.read_csv("train_add.csv")
train3 = pd.concat([train2,train_add])
```
train3を読み込み、testXの予測結果を出す

```.py
pred = model.predict(testX)
pred
```

結果は、691位。前回より悪い（泣）