今回はTitanicデータセットを使いながら、ロジスティック回帰モデルの「係数(重み)」と「StandardScaler」によるスケーリングについて学習した。
前回までにロジスティック回帰モデルを作成し、予測精度や混同行列を確認した。
今回はさらに一歩踏み込み、モデルがどのような根拠で予測しているのかを読み解く練習を行った。
前回までのモデルを振り返る
Titanicデータセットから以下の特徴量を使用して学習を行っている。
features = [
"Pclass",
"Sex",
"Age",
"Fare",
"FamilySize"
]
ロジスティック回帰では各特徴量に対して重み(係数)が割り当てられる。
まずはその値を確認してみた。
print(model.coef_) print(model.intercept_)
[[-0.92465179 2.63055403 -0.03123084 0.00363259 -0.23670432]] [1.84040515]
係数から何が読み取れるのか
係数は特徴量が予測結果へどの程度影響するかを表している。
- Pclass:-0.924
- Sex:2.631
- Age:-0.031
- Fare:0.004
- FamilySize:-0.237
今回のデータでは Sex が圧倒的に大きな値になっている。
Titanicでは女性の生存率が高かったため、モデルもその傾向を学習していることが分かる。
また Pclass は負の値になっている。
Pclassは数字が小さいほど上級客室を表すため、上級客室の乗客ほど生存率が高いという学習結果になっていると解釈できる。
ここで疑問が発生した
係数を見ると Age はほとんど影響していないように見える。
Age = -0.031 Fare = 0.003
しかし本当にそうだろうか。
ChatGPTとの壁打ちの中で気付いたのは、「単位が違う特徴量同士は係数だけで比較できない」という点である。
- Age:0〜80程度
- Fare:0〜500以上
- Sex:0か1
係数だけを比較すると誤解する可能性がある。
そこで機械学習ではスケーリングという前処理を行う。
StandardScalerを試してみる
以下のコードを実行した。
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) print(X_train_scaled[:5]) print(scaler.mean_) print(scaler.scale_)
出力結果は以下の通りである。
[[-1.61413602 -0.7243102 1.25364106 -0.07868358 -0.55466613] [-0.40055118 -0.7243102 -0.47728355 -0.37714494 -0.55466613] [ 0.81303367 -0.7243102 0.21508629 -0.47486697 -0.55466613] [ 0.81303367 -0.7243102 -0.24649361 -0.47623026 0.04009635] [ 0.81303367 1.38062393 -1.78509326 -0.02524937 3.01390875]] [ 2.33005618 0.34410112 29.20412921 32.58627612 1.93258427] [ 0.82400502 0.47507425 12.998833 51.93302107 1.68134345]
fit_transformとtransformの違い
ここで少し混乱した。
学習データには fit_transform を使っているのに、テストデータには transform しか使っていない。
理由はデータリーク防止のためである。
- fit → 平均と標準偏差を学習する
- transform → 学習した値で変換する
もしテストデータに対しても fit を実行すると、本来見るべきではない未来の情報を使ってしまうことになる。
これは実務でもKaggleでも非常に重要な考え方である。
平均を0にする意味
最初は標準偏差を揃える意味は理解できたが、平均を0にする理由がよく分からなかった。
ChatGPTとのやり取りを通して理解できたのは、「平均的なサンプルを0として扱えるようになる」という点である。
例えばAgeの平均が約29歳の場合、
29歳の人はスケーリング後に0となる。
すると、
- プラスの値 → 平均より高い
- マイナスの値 → 平均より低い
という解釈ができる。
モデルから見ると非常に扱いやすい状態になる。
スケーリング後に再学習
model_scaled = LogisticRegression(max_iter=1000) model_scaled.fit(X_train_scaled, y_train) print(model_scaled.coef_) print(model_scaled.intercept_)
[[-0.7778866 1.29427832 -0.4049586 0.18161883 -0.40699386]] [-0.666578]
見えてきたこと
スケーリング後の係数を並べると次のようになる。
- Sex:1.294
- Pclass:0.778
- FamilySize:0.407
- Age:0.405
- Fare:0.182
興味深かったのはAgeである。
スケーリング前はほとんど影響がないように見えたが、
スケーリング後に比較するとFamilySizeと同程度の重要度を持っていることが分かった。
「係数の値だけを見て判断してはいけない」という良い学びになった。
今回の学び
- ロジスティック回帰の係数は特徴量の影響度を表す
- 単位の異なる特徴量は係数だけで比較できない
- StandardScalerは平均0、標準偏差1へ変換する
- fitは学習データだけで行う
- テストデータにはtransformのみを適用する
- スケーリング後は特徴量同士を比較しやすくなる
次回予告
次回は機械学習で非常に重要な概念である「過学習(Overfitting)」について学習する予定である。
Kaggleでも実務でも避けて通れないテーマなので、しっかり理解していきたい。