Kaggleで勝つデータ分析の技術【第一章　分析コンペとは？】

#1.1分析コンペって何？

##1.1.1何をするものか

主催者から与えられたデータを用いて、データの各レコードに紐づくラベルや値を予測する分析技術を競う。

「目的変数」・・・予測する値やラベルのこと
「特徴量」　・・・目的変数を予測するために使われる様々な値
「タスク」　・・・コンペで出題される問題の内容

テストデータには特徴量のみが含まれ、目的変数がわからないようになっています。
参加者は学習データをモデルに学習させ、学習データに対するモデルでテストデータに対する予測を行います。
そのテストデータの予測値を真の値にどれくらい近づけられたかで順位が決まります。


##1.1.2予測結果の提出と順位表
コンペ期間中に参加者はテストデータの予測値を提出でき、予測値に対するスコアが表示される。

##1.1.3チームでの参加
メリット・・・各メンバーが作ったモデルの予測値の平均を取るなどの単純なアンサンブルを行うだけでもスコアが伸びる可能性があること。

#1.2分析コンペのプラットフォーム
分析今晩ぺのプラットフォームは以下のような昨日・環境を整えており、分析コンペ主催者はこれらを自前で用意することなく、コンペを開催できます。

・参加者がデータダウンロードできる
・予測値を提出すると自動的に採点する
・順位表
・スクリプト実行環境
・掲示板

◆代表的な分析コンペ
Kaggle
SIGNATE
TopCoder

##1.2.3Kernel
分析するための実行環境
DiscussionやKernelを見れば新しい知見が手に入る。

Kernelの使い方~p14~

##1.2.4Discussion
分析コンペの内容に関わる議論をする掲示板

・初心者からの質問
・ルールに関する質問
・知見や手法についての議論

##1.2.5Datasets
データセットは次の順に並び替えることができる。
・Hotness
・登録日時
・Votes数
・更新日時

Hotnessはデータの新しさとデータへのVotesなどに基づいて算出される指標
新しく登録され、注目されつつあるデータセットや、長い期間安定して注目を集めていると
Hotnessが高くなる。

データセットに含めるデータのフォーマットは一般性が高くツールに依存せずアクセスしやすい下記の形式
が推奨されている。

・csv
・json
・sqlite
・アーカイブ（zip,7zなど）
・BigQuery Dataset

#1.5上位を目指すためのポイント

##1.5.1タスクと評価指標
・タスクと評価指標
・特徴量の作成
・モデルの作成
・モデルの評価
・モデルのチューニング
・アンサンブル

```python
#学習データ、テストデータの読み込み
train = pd.read_csv('../input/titanic/train.csv')
test = pd.read_csv('../input/titanic/test.csv')

#学習データを特徴量と目的変数に分ける
train_x = train.drop(['Survived'],axis = 1)
train_y = train['Survived']

#テストデータは特徴量のみなので、そのままでいい
test_x = test.copy()
```


###データ理解（EDA）
モデルや特徴量を作る上でまず優先すべきことはデータ理解です。事前に仮設やモデルを想定せず、
データへの理解を深める意味で様々な観点からデータを見ていくことから、探索的データ分析（EDA）
と呼ばれる。
####見るべきポイント
・どういったカラムがあるのか
・各カラムの型や値の分布、欠損値、外れ値はどうなっているかを理解したり、目的変数と各変数の相関や関係性を把握することでこのあとやるべきことがわかってくる。

#####統計量
・各変数の平均/偏差値/最大/最小/分位点
・カテゴリ変数の値の種類数
・変数の欠損値の数
・変数間の相関係数

####可視化手法
・棒グラフ
・箱ひげ図、バイオリンプロット
・折れ線グラフ
・ヒートマップ
・ヒストグラム
・Q-Qプロット
・t-SNE,UMAP

kaggleではユーザーが実施したEDAの実例が多数公開されている
参考になる実例を手に入れるにはVote数が多いkernelがおすすめ

##1.5.2特徴量の作成

まず学習データに最低限の前処理を行い、モデルを学習できる形に変換する必要がある。
GBDT(勾配ブースティング木）というモデルを考える

```python
from sklearn.preprocessing import LabelEncoder

#変数PassengerIdを除外する
train_x = train_x.drop(['PassengerId'],axis=1)
test_x = test_x.drop(['PassengerId'],axis=1)

#変数Name,Ticket,Cabinを除外する
train_x = train_x.drop(['Name','Ticket','Cabin'],axis=1)
test_x =  test_x.drop(['Name','Ticket','Cabin '],axis=1)

#それぞれのカテゴリ変数にlabel encodingを適用する
for c in['Sex','Embarked']:
    #学習データに基づいてどう変換するかを定める
    le = LabelEncoder()
    le.fit(train_x[c].fillna('NA'))

    #学習データ、テストデータを変換する
    train_x[c] = le.transform(train_x[c].fillna('NA'))
    test_x[c] = le.transform(test_x[c].fillna('NA'))

```

##1.5.3モデルの作成
学習データをモデルに与えて学習させ、その後にテストデータを与えてその予測値を出力させる。
テーブルコンペでは安定して高い制度；が期待できるGBDTが主流
前回の方法で前処理した学習データをxgboostモデルに与えて学習させ、同じ方法で前処理したテストデータを与えると予測値が出力される。
スコアが0.7560であれば75%の確率で予測は当たっているということになる。


```python

from xgboost import XGBClassifier

#モデルの作成および学習データを与えての学習
model = XGBClassifier(n_estimators=20,random=71)
model.fit(x_train,y_train)

#テストデータの予測値を確率で出力する

pred = model.predict_proba(test_x)[:, 1]

#テストデータの予測値を二値に変換する
pred_label = np.where(pred>0.5,1,0)

#提出用ファイルの作成
submission = pd.DataFrame({'PassengerId':test['PassengerId'],'Survived':pred_label})
submission.to_csv('submission_first.csv',index=False)

```

##1.5.4モデルの評価
未知のデータに対して予測する性能を評価する指標が必要
一般的には学習データのvalidation(評価データ）に分ける
titanicの評価指標はaccuracyだが、accuracyは小さな改善を捉えずらいので、合わせて
loglossという指標を出力する。
loglossは予測確率が外れているほど高いペナルティが与えられ、低いほどいい指標です。
クロスバリデーションによって計算したスコアはaccuracy:0.8059,logloss: 0.4782となった。

```python
from sklearn.metrics import log_loss,accuracy_score
from sklearn.model_selection import KFold

#各foldのスコアを保存するリスト
scores_accuracy = []
scores_logloss = []

#クロスバリデーションを行う
#学習データを４つに分割し、うち一つをバリデーションデータとすることを、バリデーションデータを変えて繰り返す。
kf =KFold(n_splits=4,shuffle=True,random_state=71)
for tr_idx, va_idx in kf.split(train_x):
    #学習データを学習データとバリデーションデータに分ける
    tr_x,va_x = train_x.iloc[tr_idx],train_x.iloc[va_idx]#ilocは要素の抽出を行う
    tr_y,va_y = train_y.iloc[tr_idx],train_y.iloc[va_idx]
    
    #モデルの学習を行う
    model = XGBClassifier(n_estimators=20,random_state=71)
    model.fit(tr_x,tr_y)
    
    #バリデーションデータの予測値を確率で出力する
    va_pred = model.predict_proba(va_x)[:,1]
    
    #バリデーションデータでのスコアを計算する
    logloss = log_loss(va_y,va_pred)
    accuracy = accuracy_score(va_y,va_pred > 0.5)
    
    #そのfoldのスコアを保存する
    scores_logloss.append(logloss)
    scores_accuracy.append(accuracy)
    
#各foldのスコアの平均を出力する
logloss = np.mean(scores_logloss)
accuracy = np.mean(scores_accuracy)
print(f'logloss:{logloss: .4f},accuracy: {accuracy:.4f}')



```

##1.5.5モデルのチューニング
ハイパーパラメータと呼ばれる、学習の前に指定し、学習の方法や速度、どれだけ複雑なモデルにするか定めるパラメータがある。ここではグリッドサーチという手法でmax_depthとmin_child_weightというパラメータをチューニングしてみる。

```python
import itertools

#チューニング候補とするパラメータを準備する

param_space ={'max_depth':[3,5,7],'min_child_weight':[1.0,2.0,4.0]}

#探索するハイパーパラメータの組み合わせ
param_combinations = itertools.product(param_space['max_depth'],param_space['min_child_weight'])

#各パラメータの組み合わせ、それに対するスコアを保存するリスト
params = []
scores = []

#各パラメータの組み合わせごとに、クロスvalidationでしょうかを行う
for max_depth,min_child_weight in param_combinations:
    
    score_folds =[]
    #クロスバリデーションで行う
    #学習データを４つに分割し、うち一つをバリデーションすることを、バリデーションデータを変えて繰り返す。

    kf = KFold(n_splits=4,shuffle=True,random_state=123456)
    for tr_idx,va_idx in kf.split(train_x):
        #学習データを学習データとバリデーションデータに分ける
        tr_x,va_x = train_x.iloc[tr_idx],train_x.iloc[va_idx]
        tr_y,va_y = train_y.iloc[tr_idx],train_y.iloc[va_idx]
        
        #モデルの学習を行う
        model = XGBClassifier(n_estimators=20,random_state =71,
                              max_depth=max_depth,min_child_weight=min_child_weight)
        model.fit(tr_x,tr_y)
            
        #バリデーションデータでのスコアを計算し、保存する
        va_pred = model.predict_proba(va_x)[:,1]
        logloss = log_loss(va_y,va_pred)
        score_folds.append(logloss)
        
        #各foldのスコアを平均する
        score_mean =np.mean(score_folds)
        
        #パラメータの組み合わせ、それに対するスコアを保存する
        params.append((max_depth,min_child_weight))
        scores.append(score_mean)
#最もスコアが良いものをベストなパラメータとする
best_idx = np.argsort(scores)[0]
best_param = params[best_idx]
print(f'max_depth: {best_param[0]},min_child_weight: {best_params[1]}')
#max_depth=7,min_child_weight-2.0のスコアが最も良かった
```

##1.5.6アンサンブル
複数のモデルを組み合わせることでスコアが向上する場合があり、そのように予測することをアンサンブルと言います。アンサンブルでは、それぞれのモデルの精度が高いだけでなく、それらモデルが多様な時にスコアが向上しやすいです。前項までに作成したxgboostモデルとロジスティック回帰モデルの予測値の平均とってアンサンブルをしてみます。


```python
from sklearn.linear_model import LogisticRegression

#xgboostモデル
model_xgb = XGBClassifier(n_estimators=20,random_state=71)
model_xgb.fit(train_x,train_y)
pred_xgb = model_xgb.predict_proba(test_x)[:,1]

#ロジスティック回帰モデル
#xgboostモデルとは異なる特徴量を入れる必要があるので、別途train_x2,test_x2を作成した
model_lr = LogisticRegression(solver = 'lbfgs',max_iter=300)
model_lr.fit(train_x2,train_y)
pred_lr = model_lr.predict_proba(test_x2)[:,1]

#予測値の加重平均をとる
pred = pred_xgb * 0.8 +pred_lr * 0.2
pred_label = np.where(pred>0.5,1,0)

```

##1.5.7分析コンペの流れ
ここまでタイタニックデータを用いて分析コンペにおけるポイントを概観したが、基本的なテクニックを用いて最低限の分析をするのみとなっています。

基本的には以下のようなサイクルで進んでいく
1.特徴量を作成する
2.作成した特徴量をそれまでの特徴量に加え、モデルの学習を行う
3.予測が改善したかどうかバリデーションで評価する

この他にもEDAでデータの理解を深めて特徴量作成のヒントを得たり、異なるモデルでもを使ったり、パラメータチューニングを行ったり、アンサンブルを行なってスコアを伸ばしたりします。