前回、決定木モデルで70%の精度でした。
今回はロジスティック回帰を使って予測してみようと思います。
私が一番好きなモデルで実業務でもよく使っています。
評価指標
タイタニックのデータセットは生存有無を正確に予測できた乗客の割合(Accuracy)を評価指標としています。
ロジスティック回帰
分析用データの準備
事前に欠損値処理や特徴量エンジニアリングを実施してデータをエクスポートしています。
本記事と同じ結果にするためには事前に下記記事を確認してデータを用意してください。
学習データと評価データの読み込み
概要確認
RangeIndex: 891 entries, 0 to 890 Data columns (total 22 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 PassengerId 891 non-null int64 1 Survived 891 non-null int64 2 Pclass 891 non-null int64 3 Name 891 non-null object 4 Sex 891 non-null object 5 Age 891 non-null float64 6 SibSp 891 non-null int64 7 Parch 891 non-null int64 8 Ticket 891 non-null object 9 Fare 891 non-null float64 10 Cabin 204 non-null object 11 Embarked 891 non-null object 12 FamilyCnt 891 non-null int64 13 SameTicketCnt 891 non-null int64 14 Pclass_str_1 891 non-null float64 15 Pclass_str_2 891 non-null float64 16 Pclass_str_3 891 non-null float64 17 Sex_female 891 non-null float64 18 Sex_male 891 non-null float64 19 Embarked_C 891 non-null float64 20 Embarked_Q 891 non-null float64 21 Embarked_S 891 non-null float64 dtypes: float64(10), int64(7), object(5) memory usage: 153.3+ KB
RangeIndex: 418 entries, 0 to 417 Data columns (total 21 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 PassengerId 418 non-null int64 1 Pclass 418 non-null int64 2 Name 418 non-null object 3 Sex 418 non-null object 4 Age 418 non-null float64 5 SibSp 418 non-null int64 6 Parch 418 non-null int64 7 Ticket 418 non-null object 8 Fare 418 non-null float64 9 Cabin 91 non-null object 10 Embarked 418 non-null object 11 Pclass_str_1 418 non-null float64 12 Pclass_str_2 418 non-null float64 13 Pclass_str_3 418 non-null float64 14 Sex_female 418 non-null float64 15 Sex_male 418 non-null float64 16 Embarked_C 418 non-null float64 17 Embarked_Q 418 non-null float64 18 Embarked_S 418 non-null float64 19 FamilyCnt 418 non-null int64 20 SameTicketCnt 418 non-null int64 dtypes: float64(10), int64(6), object(5) memory usage: 68.7+ KB
モデル作成
max_iterの値を1000にしています。
これは最初にfitしたときに下記エラー?警告?に遭遇したためです。
Increase the number of iterations (max_iter) or scale the data as shown in:
デフォルトの値(max_iter=100)だと警告が出てくるので、iterの回数を上げています。
ただ上げても精度は変わらなかったです。
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers. This problem is unconstrained. ・・・省略・・・ Tit = total number of iterations Tnf = total number of function evaluations Tnint = total number of segments explored during Cauchy searches Skip = number of BFGS updates skipped Nact = number of active bounds at final generalized Cauchy point Projg = norm of the final projected gradient F = final function value * * * N Tit Tnf Tnint Skip Nact Projg F 9 104 121 1 0 0 9.765D-02 3.172D+02 X = -3.8864D-02 3.1145D-03 -1.9699D-01 8.1966D-01 -1.3555D+00 2.4869D+00 -7.4909D-02 -4.1107D-01 6.8544D-01 F = 317.22127537805329 CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH
モデルの精度の確認
0.8117977528089888
0.7988826815642458
訓練データとテストデータへの当てはまりを確認しましたが、そこまで差がなさそうなのでオーバーフィットはしていなさそうです。
デフォルトの設定の正則化でいい感じに学習してくれているだと思います。
TP(正解=1、予測=1)とFP(正解=0、予測=0)の割合を確認。意外とTPを当てることが出来ていそう。
{'C': 1.0, 'class_weight': None, 'dual': False, 'fit_intercept': True, 'intercept_scaling': 1, 'l1_ratio': None, 'max_iter': 1000, 'multi_class': 'auto', 'n_jobs': None, 'penalty': 'l2', 'random_state': 0, 'solver': 'lbfgs', 'tol': 0.0001, 'verbose': 3, 'warm_start': False}
係数と切片の確認
features coef 0 Age -0.038864 1 Fare 0.003114 2 SameTicketCnt -0.196987 3 Pclass_str_1 0.819655 4 Pclass_str_3 -1.355546 5 Sex_female 2.486910 6 Embarked_Q -0.074909 7 Embarked_S -0.411074
女性であることやPclass=1であることは符号がプラスなので生存に関わっていそうです。
ここで符号の反転などが起きている場合(Pclass=1なのに係数がマイナスなど)は不安定なモデルと判断し、私は使わないことにしています。
変数間の値の比較はデータを標準化していれば可能だと思います。
今回は標準化せずにモデリングしてしまったので、標準化バージョンもやってみようと思います。
Intercept = 0.6854377614688429
ここで出てくる係数や切片を数式に落とし込みシステムへ導入するなんてことも出来るかと思います。
クロスバリデーションで精度を確認
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers. [Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers. This problem is unconstrained. ・・・省略・・・ 0.8036204744069912 8956D-01 F = 359.97764259905961 CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH
精度は80%でした。
Kaggle提出用データの作成
Kaggleへアップロード
100%|████████████████████████████████████████| 2.77k/2.77k [00:04<00:00, 586B/s] Successfully submitted to Titanic - Machine Learning from Disaster
コンペの精度確認
75%になりました!
データを標準化した場合としない場合の比較
sklearnのロジスティック回帰(sklearn version 1.0.2)では過学習を防ぐためにL2正則化(L2 regularization)がデフォルトで使用されています。
正則化に関してはRidgeとLassoの記事が分かりやすかったです。
正則化ではマンハッタン距離やユークリッド距離が関係するようで、距離の計算をする都合上データの標準化をした方がいいようです。
また、Elements of Statistical Learningという図書でも正則化の際はデータを正規化することを推奨しているようです。
Regularization makes the predictor dependent on the scale of the features.
The authors of Elements of Statistical Learning recommend to normalize the features when doing logistic regression with regularization
https://stats.stackexchange.com/questions/290958/logistic-regression-and-scaling-of-features
ということで、標準化をしてからモデルに学習データを渡してあげてみます。
標準化 (pipeline + StandardScaler)
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers. ・・・省略・・・ N Tit Tnf Tnint Skip Nact Projg F 9 11 12 1 0 0 9.252D-04 3.138D+02 X = -5.3102D-01 1.3868D-01 -2.6803D-01 3.7883D-01 -7.0413D-01 1.2292D+00 -2.7997D-02 -1.9567D-01 -7.1526D-01 F = 313.81239604323093 CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH
iterationの数が減ったような気がします。標準化の効果でしょうか。
0.8103932584269663
あとで比較しますが、標準化しなかった場合より精度が若干下がっています。
オーバーフィットが若干和らいでいるのかも知れません。
0.7988826815642458
テストデータへの精度は変わりないようです。
{'memory': None, 'steps': [('standardscaler', StandardScaler()), ('logisticregression', LogisticRegression(max_iter=1000, random_state=0, verbose=3))], 'verbose': False, 'standardscaler': StandardScaler(), 'logisticregression': LogisticRegression(max_iter=1000, random_state=0, verbose=3), 'standardscaler__copy': True, 'standardscaler__with_mean': True, 'standardscaler__with_std': True, 'logisticregression__C': 1.0, 'logisticregression__class_weight': None, 'logisticregression__dual': False, 'logisticregression__fit_intercept': True, 'logisticregression__intercept_scaling': 1, 'logisticregression__l1_ratio': None, 'logisticregression__max_iter': 1000, 'logisticregression__multi_class': 'auto', 'logisticregression__n_jobs': None, 'logisticregression__penalty': 'l2', 'logisticregression__random_state': 0, 'logisticregression__solver': 'lbfgs', 'logisticregression__tol': 0.0001, 'logisticregression__verbose': 3, 'logisticregression__warm_start': False}
「steps」という項目が増えていますね
pipelineだと係数(model.coef_)が確認できないので、モデルをpipelineから取り出しておきます。
{'C': 1.0, 'class_weight': None, 'dual': False, 'fit_intercept': True, 'intercept_scaling': 1, 'l1_ratio': None, 'max_iter': 1000, 'multi_class': 'auto', 'n_jobs': None, 'penalty': 'l2', 'random_state': 0, 'solver': 'lbfgs', 'tol': 0.0001, 'verbose': 3, 'warm_start': False}
features coef coef_pct 5 Sex_female 1.229169 0.353867 4 Pclass_str_3 -0.704128 0.202712 0 Age -0.531025 0.152877 3 Pclass_str_1 0.378831 0.109062 2 SameTicketCnt -0.268033 0.077164 7 Embarked_S -0.195670 0.056332 1 Fare 0.138682 0.039925 6 Embarked_Q -0.027997 0.008060
標準化前と係数の値は変更になっていますが、序列は変わってないように見えます。
標準化することによって、変数間の比較も可能になったので寄与度(coef_pct)を計算してみました。
女性であること、Pclass=3であること、年齢が予測に寄与しているようです。
これは映画タイタニックのセリフであった、女性と子供を優先して救命ボートに乗せるに合致していますね。
標準化 (StandardScalerのみ)
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers. ・・・省略・・・ N Tit Tnf Tnint Skip Nact Projg F 9 11 12 1 0 0 9.252D-04 3.138D+02 X = -5.3102D-01 1.3868D-01 -2.6803D-01 3.7883D-01 -7.0413D-01 1.2292D+00 -2.7997D-02 -1.9567D-01 -7.1526D-01 F = 313.81239604323093 CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH
0.8103932584269663
pipelineを使った場合と変わりないようです。
0.7988826815642458
こちらもpipelineを使った場合と変わりないようです。
features coef coef_pct 5 Sex_female 1.229169 0.353867 4 Pclass_str_3 -0.704128 0.202712 0 Age -0.531025 0.152877 3 Pclass_str_1 0.378831 0.109062 2 SameTicketCnt -0.268033 0.077164 7 Embarked_S -0.195670 0.056332 1 Fare 0.138682 0.039925 6 Embarked_Q -0.027997 0.008060
pipelineの結果と変わりありません。
標準化なし、標準化あり(pipeline)、標準化あり(StandardScalerのみ)の結果比較
#1:正規化なしver [[90 14] [22 53]] #2:正規化あり+pipeline [[90 14] [22 53]] #3:正規化あり [[90 14] [22 53]]
テストデータへの結果は変わりません。
#1:正規化なしver 0.8117977528089888 #2:正規化あり+pipeline 0.8103932584269663 #3:正規化あり 0.8103932584269663
オーバフィットが軽減できているようです。
kaggleへアップロードする用のデータへの当てはまりは若干よくなるかもしれません。
#1:正規化なしver 0.7988826815642458 #2:正規化あり+pipeline 0.7988826815642458 #3:正規化あり 0.7988826815642458
テストデータに対する精度は変わりませんでした。
Kaggleへ標準化verのモデルをアップロード
100%|████████████████████████████████████████| 2.77k/2.77k [00:04<00:00, 591B/s] Successfully submitted to Titanic - Machine Learning from Disaster
model #002. logistic regression (normalized) 0.76076
なんと良くなりました。
標準化しなかった場合が、0.75837だったので少しよくなったようです。
まとめ
ロジスティック回帰の結果は標準化した場合で76%でした。
前回より精度が上がりました。
本当は変数の組み合わせやオプションの組み合わせを変更して色々試してみたいところです。
一通りの手法を試してみたらやってみたいと思います。
追記
ロジスティック回帰のパラメーターの最適化をクロスバリデーションで実施し、精度が若干向上しました。