[Kaggle] Intermediate Machine Learning

#KaggleのCourse
Kaggleには初学者（？）向けの、Courseと呼ばれるデータサイエンスの基礎となる部分を解説してくれるページがあります。これは解説と実装を体験できる仕組みになっおり、データサイエンス初学者の自分はこれを勉強しようと考え取り組みました。その備忘録として簡単にメモしていたものをまとめてみました。

KaggleのCourseを読む前のAbstract程度に読んでいただけたら幸いです。
#Missing Values
機械学習を行う前のデータの前処理について。データの抜けのことををmissing valueと言っている。ここでmissing value にも様々な要因がある。
データの欠落において
・無という情報を表している
・意図的に情報がない
の2点では意味が異なるので注意が必要。

欠損値があるのかを判定するコードは次の通り。

```python
#1つでも欠損値であるかを判定
DataFrame.isnull().any()

```
代入処理をするオブジェクトSimpleImputerの使い方はこんな感じ。
strategyを'constant'にすると、fill_valueで与えた定数を代入する。
fill_valueはデフォルトでNoneだが、Noneのときは数値なら0,文字列ならmissing_valueが代入されるはず。

```python
from sklearn.impute import SimpleImputer
imputer = SimpleImputer()
imputer.fit(df)
#dfにimputerをfit
result = imputer.transform(df) 
#dfを処理してresultに格納
SimpleImputer(missing_values=np.nan, strategy='mean', fill_value=None)

```

```python
DataFrame.copy()
#値をコピー
#＝を使うと参照渡しとなって、元の数値までかわってしまう
```

行や列を削除するときの属性はdropやdropna

```python
data.dropna() 
#欠損値を含む行列を削除
how = 'all'
#すべての値がNaNで削除
how='any'
#1つでもNaNなら削除
axis = 0
#デフォルトで行に適用
axis=1
#列に適用
inplace = True
#元のデータに変更を反映

data.drop('行の名前',axis=0)
#行列を指定して削除
```

#Categorical Variable


DataFrameのSeriesオブジェクトはbool型のリストやSeriesを渡すと([True,False,...])
Trueの順番の要素だけを指定できる。

Seriesのユニークな値の見方。

```python
DataFrameの列(=Series).unique()
#その列に含まれる値を表示する
Series.value_counts()
#中身の要素がindexに、その個数がデータとなる
Series.nunique()
#ユニークな値の個数
```

labelencodingのオブジェクトの使い方。

```python
from sklearn.preprocessing import LabelEncoder
label_encoder = LabelEncoder()
label_encoder.fit_transform(Series
label_encoder.transform(Series)
#DataFrameの列を渡す。渡した列をラベリングに変える。
```

One-Hot encodingの使い方。

```python
from sklearn.preprocessing import OneHotEncoder

OH_encoder = OneHotEncoder(handle_unknown='ignore', sparse=False)
#OneHotEncoderはarray型を返すのでdata型に変換しつつ格納
OH_cols_train=pd.DataFrame(OH_encoder.fit_transform(X_train[low_cardinality_cols]))
#data型にしたものはindexついていないので、それを追加
# One-hot encoding removed index; put it back
OH_cols_train.index = X_train.index

#OHencodingした列を元のデータから削除
# Remove categorical columns (will replace with one-hot encoding)
num_X_train = X_train.drop(object_cols, axis=1)

#OHencodingだけのDataFrameと元のDataFrameからOH列を落としたものを合体
# Add one-hot encoded columns to numerical features
OH_X_train = pd.concat([num_X_train, OH_cols_train], axis=1)

```

#Pipeline
Pipelineは煩雑なデータの前処理を1つにまとめるためのオブジェクト。
以下ではPipelineオブジェクトとColumnTransformerオブジェクトを作っている。
[この記事](https://qiita.com/shota-imazeki/items/4a69e4ef2f12e0313495)がPipelineの中身が詳しく書いてある。
OHはデータのdropまでやっているみたい。fit_transform後のデータにカテゴリカル変数はなかったから。

```python
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder

# 数値データに代入処理をするオブジェクト
numerical_transformer = SimpleImputer(strategy='constant')

# カテゴリカルデータに対し、Nanに代入をして、その後OHエンコーダをする。
#stepにtaple型で処置を渡す。
#step=[('処理の名前',処理オブジェクト(引数),...)]
categorical_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')),
    ('onehot', OneHotEncoder(handle_unknown='ignore'))
])

# 列ごと（特徴量ごと）にColumnTransformerで処理をする
#transformers=[('処理の名前（なんでも）',処理オブジェクト,この処理を施す列(特徴量)の名前),...()]
preprocessor = ColumnTransformer(
    transformers=[
        ('num', numerical_transformer, numerical_cols),
        ('cat', categorical_transformer, categorical_cols)
    ])
```

#Cross Validation
交差検証という。データセットを単純に2分割すると、検証データと訓練データの分け方によって、モデルの精度が異なってしまう問題が生じる。検証データが１つなら、計算される精度はほぼ運になってしまう。検証データが多くなるとその信頼度が上がり、訓練データが多くなるとモデルの正確さが増す。２分割にする場合これらはトレードオフの関係にある。

そこで次のような図のからなる交差検証を行う。交差検証では下の分割を5"folds"と呼ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1144777/c9e23237-35e5-0dfc-519c-fad8c7cd3b42.png)
一般に小さいデータセットの時に交差検証を行うと効果的である。これは計算時間が増えるからであり（上の図なら約５倍）、2分以内の計算時間で終わるのであれば交差検証にするほうがよいことが多い。
また交差検証のfoldごとの評価値を見て、それらに大きな差がないのであれば交差検証を使う必要はないことが多い。

```python
from sklearn.model_selection import cross_val_score

# cross_val_score(モデルオブジェクト,X,y,cv=foldの数,scoring=MAEのような評価方法)
scores = -1 * cross_val_score(my_pipeline, X, y,
                              cv=5,
                              scoring='neg_mean_absolute_error')
```

#XGBoost

```python
from xgboost import XGBRegressor

my_model = XGBRegressor()
my_model.fit(X_train, y_train)
predictions = my_model.predict(X_valid)
```

XGBはいろいろなパラメータを持っているが、その中でも影響が強いものを紹介する。
<n_estimators>
アンサンブル学習のループ回数。または追加するモデルの数。
大きい→過学習
小さい→アンダーフィッティング
＜early_stopping_rounds＞
n_estimatorsを最適化計算で求める際に、損失関数が何回悪化したら計算をやめるかの数。
early_stopping_rounds=5が標準くらい。
検証データとしてeval_setにX_validとy_validを渡す。
＜learning_rate＞
損失関数を減少させるステップ幅。小さいと収束が遅くなる。大きいと損失関数が増加してしまうことがある。
＜n_jobs＞
並列処理をさせるCPUの数。計算が速くなる。

```python
my_model = XGBRegressor(n_estimators=1000, learning_rate=0.05, n_jobs=4)
my_model.fit(X_train, y_train, 
             early_stopping_rounds=5, 
             eval_set=[(X_valid, y_valid)], 
             verbose=False)
```

#Data leakage
#####Target leakage
target leakageは予測に使えないデータが紛れ込んでいることを指している。
表では肺炎(pneumonia)になった人を予測するのだが、そのデータに肺炎の治療薬を摂取したかどうかは使えない。むしろ肺炎になったのだから、治療薬はほぼ摂取していることになり、学習段階では効果的な特徴量とみなされてしまう。
![Screenshot from 2021-03-14 19-56-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1144777/6811eafe-89ba-3899-3b4f-ec297619fffb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1144777/0f77a6f0-e4ae-e6bb-941d-c97e96fb32a0.png)

[引用元:Kaggle | Data Leakage](https://www.kaggle.com/alexisbcook/data-leakage)

#####Train-Test Contamination

検証データと訓練データを分ける前に前処理（SimpleImputerなど）をすると、検証時のスコアは改善するが、実際に予測するときに性能落ちてしまう。これを防ぐためには前処理を含めて、検証データをフィッティングしないことが大切である。