【Python】データ分析、機械学習実践(Kaggle)〜モデル解析編〜

# はじめに
前回の記事[
【Python】初めての データ分析・機械学習（Kaggle）](https://qiita.com/Julio_dev/items/8d77e3d18883e4bbbe24)
[【Python】初めての データ分析・機械学習（Kaggle）〜Part2〜](https://qiita.com/Julio_dev/items/4754a8dc545b7023e8c1)
に引き続き、Kaggleで比較的優しいコンペ「[House Prices: Advanced Regression Techniques](https://www.kaggle.com/c/house-prices-advanced-regression-techniques)」に挑戦しました！

今回のコンペは、住宅に関する情報の変数をもとに、住宅の価格を推定するというもの。
しかし、この住宅に関する変数が80もあり、いきなり怖気付きました、、(笑)

「こんなのできるのか、、？」て思いつつ、今回もしっかり先人の知恵を借りました！笑
参考コード↓↓↓

- [Stacked Regressions : Top 4% on LeaderBoard](https://www.kaggle.com/serigne/stacked-regressions-top-4-on-leaderboard)
- [Comprehensive data exploration with Python](https://www.kaggle.com/pmarcelino/comprehensive-data-exploration-with-python)

大まかな流れは、以下のようになっています。

1. 特徴エンジニアリング
    1. **Imputing missing values** 欠損値の穴埋め
    2. **Transforming** データ変換(log変換等)
    3. **Label Encoding** カテゴリカルデータのエンコード
    4. **Box Cox Transformation** : 正規分布に近づけさせるための変換
    5. **Getting dummy variables** カテゴリカルデータを数値データへ
2. モデリング(スタッキングアンサンブル学習)
    1. ベースモデル解析
    2. 第２モデル解析


そして、本記事では、 **モデリング** に焦点を当てていきます！
ですから、Kaggleのコンペの予測値まで出力するところまで行きます！！

前回の**特徴エンジニアリング**に関する記事はこちら↓↓↓
[【Python】データ分析、機械学習実践(Kaggle)〜データ前処理編〜](https://qiita.com/Julio_dev/items/7160fcfce871dcbf57e6)

# 1. ライブラリのインポート

今回も[Titanicの時](https://qiita.com/Julio_dev/items/4754a8dc545b7023e8c1)と同様にスタッキングアンサンブル学習で予測する。

使用するモデル
1. LASSO Regression
2. Elastic Net Regression
3. Kernel Ridge Regression
4. Gradient Boosting Regression
5. XGBoost
6. LightGBM


###学習の流れ

1. ４つのモデルを平均する
    1. LASSO Regression
    2. Elastic Net Regression
    3. Kernel Ridge Regression
    4. Gradient Boosting Regression

2. **1.で平均したモデル**と**XGBoost**と**LightGBM**の３つでスタックして最終的な予測を行う

<img width="536" alt="スクリーンショット 2020-03-20 10.45.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383306/ce4a97e5-0c82-9e83-9247-2f5e172e5e17.png">





```python
from sklearn.linear_model import ElasticNet, Lasso,  BayesianRidge, LassoLarsIC
from sklearn.ensemble import RandomForestRegressor,  GradientBoostingRegressor
from sklearn.kernel_ridge import KernelRidge
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import RobustScaler
from sklearn.base import BaseEstimator, TransformerMixin, RegressorMixin, clone
from sklearn.model_selection import KFold, cross_val_score, train_test_split
from sklearn.metrics import mean_squared_error
import xgboost as xgb
import lightgbm as lgb
```

#2. 交差検証の定義

k=5（データ群を５分割）として
モデルの評価は**対数平均二乗誤差(RMSLE)**で行います。
**スコアが小さいほど精度が高い**という見方です！

```python
#Validation function
n_folds = 5

def rmsle_cv(model):
    kf = KFold(n_folds, shuffle=True, random_state=42).get_n_splits(train.values) #シャッフル
    rmse= np.sqrt(-cross_val_score(model, train.values, y_train, scoring="neg_mean_squared_error", cv = kf))
    return(rmse)

def rmsle(y, y_pred):
    return np.sqrt(mean_squared_error(y, y_pred))
```


#3.平均するモデリング

1. 4つのモデルの平均(ベースモデルEnet・KRR・Gboost,メタモデル=lasso)
2. XGBoost
3. LightGBM

この３つをスタッキングします！

まずは、1. 4つのモデルの平均(ベースモデルEnet・KRR・Gboost,メタモデル=lasso)から！


```python
class StackingAveragedModels(BaseEstimator, RegressorMixin, TransformerMixin):
    def __init__(self, base_models, meta_model, n_folds=5):
        self.base_models = base_models
        self.meta_model = meta_model
        self.n_folds = n_folds
   
    # モデルのクローンにデータをfitさせる
    def fit(self, X, y):
        self.base_models_ = [list() for x in self.base_models]
        self.meta_model_ = clone(self.meta_model)
        kfold = KFold(n_splits=self.n_folds, shuffle=True, random_state=156)
        
        # 学習ベースモデルがフォールド外予測をします
        # そのフォールド外予測はメタモデルで必要となります
        out_of_fold_predictions = np.zeros((X.shape[0], len(self.base_models)))
        for i, model in enumerate(self.base_models):
            for train_index, holdout_index in kfold.split(X, y):
                instance = clone(model)
                self.base_models_[i].append(instance)
                instance.fit(X[train_index], y[train_index])
                y_pred = instance.predict(X[holdout_index])
                out_of_fold_predictions[holdout_index, i] = y_pred
                
        # フォールド外予測を用いてメタモデルの学習
        self.meta_model_.fit(out_of_fold_predictions, y)
        return self
   
    #全てのベースモデルの予測値と予測の平均値をメタ特徴として、メタモデルで最終予測を行います!
    def predict(self, X):
        meta_features = np.column_stack([
            np.column_stack([model.predict(X) for model in base_models]).mean(axis=1)
            for base_models in self.base_models_ ])
        return self.meta_model_.predict(meta_features)
```

ベースモデルEnet・KRR・Gboost,メタモデル=lassoで適応します。

```python
stacked_averaged_models = StackingAveragedModels(base_models = (ENet, GBoost, KRR),
                                                 meta_model = lasso)

score = rmsle_cv(stacked_averaged_models)
print("Stacking Averaged models score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
```

```text:出力
Stacking Averaged models score: 0.1085 (0.0074)
```
平均したモデルを**rmsle()**で評価します！

```python
stacked_averaged_models.fit(train.values, y_train)
stacked_train_pred = stacked_averaged_models.predict(train.values)
stacked_pred = np.expm1(stacked_averaged_models.predict(test.values))
print(rmsle(y_train, stacked_train_pred))
```

```text:出力
0.0781571937916
```

#4. 平均しないモデリング

平均しない**XGBoost**と**LightGBM**のモデルで学習・テスト・評価します！

###XGBoost

```python
#学習
model_xgb.fit(train, y_train)
xgb_train_pred = model_xgb.predict(train)
#テスト
xgb_pred = np.expm1(model_xgb.predict(test))
#評価
print(rmsle(y_train, xgb_train_pred))
```

```text:出力
0.0785165142425
```

###LightGBM

```python
model_lgb.fit(train, y_train)
lgb_train_pred = model_lgb.predict(train)
lgb_pred = np.expm1(model_lgb.predict(test.values))
print(rmsle(y_train, lgb_train_pred))
```

```text:出力
0.0716757468834
```

#5. 平均モデルとXGBoostとLightGBMをスタッキング



```python
'''RMSE on the entire Train data when averaging'''

print('RMSLE score on train data:')
print(rmsle(y_train,stacked_train_pred*0.70 +
               xgb_train_pred*0.15 + lgb_train_pred*0.15 ))
```

```text:出力
RMSLE score on train data:
0.0752190464543
```

###アンサンブル学習
```python
ensemble = stacked_pred*0.70 + xgb_pred*0.15 + lgb_pred*0.15
```

#6. Kaggleの提出

```python
sub = pd.DataFrame()
sub['Id'] = test_ID
sub['SalePrice'] = ensemble
sub.to_csv('submission.csv',index=False)
```

#最後に
今回参考にした[Stacked Regressions : Top 4% on LeaderBoard](https://www.kaggle.com/serigne/stacked-regressions-top-4-on-leaderboard)では、説得力を増すための補足的なコーディングが多かったので、本記事ではかなりシンプルに書きました！

ただし、人のコードを参考にしただけなので、自分でもまだ消化し切れていない部分があります、、
例えば、

- 各モデルの利用根拠
- 最後にスタッキングする際に、重みを「0.7,0.15,0.15」にした理由

などがよくわかっていませんので、もしもわかる方がいらっしゃいましたらコメントで教えていただきたいです😣


おかしな記述があるかもしれませんが、少しでもモデリングについて参考になれば幸いです！！