クレジットカード申請承認予測¶

商業銀行はクレジット カードの申し込みを 大量 に受け取ります。その多くは、ローン残高が多い、収入レベルが低い、個人の信用報告書の照会が多すぎるなど、さまざまな理由で拒否されます。これらのアプリケーションを手動で分析するのは日常的で、エラーが発生しやすく、時間がかかります (時は金なりです!)。幸いなことに、このタスクは機械学習の力で自動化することができ、現在ではほぼすべての商業銀行が自動化しています。
実際の銀行が行うのと同じように、機械学習技術を使用して自動クレジット カード承認予測ツールを構築します。

cardwithhand

カリフォルニア大学アーバイン校 Machine Learning リポジトリの クレジット カード承認データセット を使用します。

  1. データセットをロードする
  2. データセットには数値と非数値の両方の特徴が混在していること、さまざまな範囲の値が含まれていること、さらに多数の欠落エントリが含まれていることを検証する
  3. 選択した機械学習モデルが適切な予測を行えるようにするために、データセットを前処理(クリーニング)する
  4. データの状態が整ったら、直感を構築するために探索的なデータ分析
  5. 個人のクレジット カードの申請が受け付けられるかどうかを予測できる機械学習モデルを構築

1. データセットを取得¶

ウェブサイトからデータセットをロードして表示します。
zipファイルであるため、必要なライブラリをインポートして、データを取得します。

from zipfile import ZipFile
from io import BytesIO
import pandas as pd
import requests
url = "https://archive.ics.uci.edu/static/public/27/credit+approval.zip"
buf = BytesIO(requests.get(url).content)

with ZipFile(buf, "r") as f:
    for name in f.namelist():
        print('File name : ',name)
        if name.endswith('.data'):
            with f.open(name) as zd:
                cc_apps = pd.read_csv(zd, encoding='utf-8', sep=',', header=None)
            print(cc_apps.head())
            break
    else: print('Not found data')
File name :  Index
File name :  credit.lisp
File name :  credit.names
File name :  crx.data
  0      1      2  3  4  5  6     7  8  9   10 11 12     13   14 15
0  b  30.83  0.000  u  g  w  v  1.25  t  t   1  f  g  00202    0  +
1  a  58.67  4.460  u  g  q  h  3.04  t  t   6  f  g  00043  560  +
2  a  24.50  0.500  u  g  q  h  1.50  t  f   0  f  g  00280  824  +
3  b  27.83  1.540  u  g  w  v  3.75  t  t   5  t  g  00100    3  +
4  b  20.17  5.625  u  g  w  v  1.71  t  f   0  f  s  00120    0  +

このデータは機密であるため、データセットの提供者が特徴名(カラム名)を匿名化していることがわかりましたのでリセットして取得し直します。

2. データセットの検証¶

出力は一見すると少し混乱しているように見えますが、クレジット カード アプリケーションの最も重要な機能を理解してみましょう。
このデータセットの特徴はプライバシーを保護するために匿名化されていますが、このブログ では、考えられる特徴のかなり良い概要が得られます。
典型的なクレジット カード アプリケーションで考えられる特徴は、Gender, Age, Debt, Married, BankCustomer, EducationLevel, Ethnicity, YearsEmployed, PriorDefault, Employed, CreditScore, DriversLicense, Citizen, ZipCode, Income、そして最後に ApprovalStatus です。
これは非常に良い出発点となり、出力の列に関してこれらの特徴をマッピングできます。

データを一目見てわかるように、データセットには数値的特徴と非数値的特徴が混在しています。これは前処理を行うことで修正できますが、その前に、データセットについてもう少し詳しく学び、修正する必要のあるデータセットの問題が他にあるかどうかを確認してみます。

print(cc_apps.describe())
print("\n")

print(cc_apps.info())
print("\n")

print(cc_apps.tail(17))
               2           7          10             14
count  690.000000  690.000000  690.00000     690.000000
mean     4.758725    2.223406    2.40000    1017.385507
std      4.978163    3.346513    4.86294    5210.102598
min      0.000000    0.000000    0.00000       0.000000
25%      1.000000    0.165000    0.00000       0.000000
50%      2.750000    1.000000    0.00000       5.000000
75%      7.207500    2.625000    3.00000     395.500000
max     28.000000   28.500000   67.00000  100000.000000


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 690 entries, 0 to 689
Data columns (total 16 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   0       690 non-null    object 
 1   1       690 non-null    object 
 2   2       690 non-null    float64
 3   3       690 non-null    object 
 4   4       690 non-null    object 
 5   5       690 non-null    object 
 6   6       690 non-null    object 
 7   7       690 non-null    float64
 8   8       690 non-null    object 
 9   9       690 non-null    object 
 10  10      690 non-null    int64  
 11  11      690 non-null    object 
 12  12      690 non-null    object 
 13  13      690 non-null    object 
 14  14      690 non-null    int64  
 15  15      690 non-null    object 
dtypes: float64(2), int64(2), object(12)
memory usage: 86.4+ KB
None


    0      1       2  3  4   5   6      7  8  9   10 11 12     13   14 15
673  ?  29.50   2.000  y  p   e   h  2.000  f  f   0  f  g  00256   17  -
674  a  37.33   2.500  u  g   i   h  0.210  f  f   0  f  g  00260  246  -
675  a  41.58   1.040  u  g  aa   v  0.665  f  f   0  f  g  00240  237  -
676  a  30.58  10.665  u  g   q   h  0.085  f  t  12  t  g  00129    3  -
677  b  19.42   7.250  u  g   m   v  0.040  f  t   1  f  g  00100    1  -
678  a  17.92  10.210  u  g  ff  ff  0.000  f  f   0  f  g  00000   50  -
679  a  20.08   1.250  u  g   c   v  0.000  f  f   0  f  g  00000    0  -
680  b  19.50   0.290  u  g   k   v  0.290  f  f   0  f  g  00280  364  -
681  b  27.83   1.000  y  p   d   h  3.000  f  f   0  f  g  00176  537  -
682  b  17.08   3.290  u  g   i   v  0.335  f  f   0  t  g  00140    2  -
683  b  36.42   0.750  y  p   d   v  0.585  f  f   0  f  g  00240    3  -
684  b  40.58   3.290  u  g   m   v  3.500  f  f   0  t  s  00400    0  -
685  b  21.08  10.085  y  p   e   h  1.250  f  f   0  f  g  00260    0  -
686  a  22.67   0.750  u  g   c   v  2.000  f  t   2  t  g  00200  394  -
687  a  25.25  13.500  y  p  ff  ff  2.000  f  t   1  t  g  00200    1  -
688  b  17.92   0.205  u  g  aa   v  0.040  f  f   0  f  g  00280  750  -
689  b  35.00   3.375  u  g   c   h  8.290  f  f   0  t  g  00000    0  -

3. データセットのクリーニング¶

欠損値の処理 1¶

機械学習モデルを変更しないとパフォーマンスに影響を及ぼす可能性があるいくつかの問題が判明しました。

  • データセットには、数値データと非数値データの両方が含まれています (具体的には、float64、int64、および object 型のデータ)。具体的には、機能 2、7、10、および 14 には数値(float64、 int64) が含まれており、他のすべての機能には数値以外の値が含まれています。
  • データセットには、いくつかの範囲の値も含まれています。 一部の特徴の値の範囲は 0 ~ 28、一部の範囲は 2 ~ 67、一部の特徴の範囲は 1017 ~ 100000 です。これらとは別に、有用な統計情報 (平均、最大、最小など) を取得できます。数値を持つ特徴。
  • データセットには欠損値が存在しているため処理が必要です。データセット内の欠損値には「?」のラベルが付けられており、最後のセルの出力で確認できます。

? を含むデータの存在を視覚化すると、(黒い部分に)多数含まれていることがわかります。

import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 6))
sns.heatmap(cc_apps.applymap(lambda x: x == '?'), cmap="YlGnBu", cbar_kws={'label': 'include `?` mark'})

plt.show()
question_mark_counts = cc_apps.applymap(lambda x: isinstance(x, str) and '?' in x).sum()

pd.DataFrame({'Number_of_question_mark': question_mark_counts}).T
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Number_of_question_mark 12 12 0 6 6 9 9 0 0 0 0 0 0 13 0 0

具体的には各カラムに上記の数の ? が含まれていることがわかりました。

これらの欠損値である ? を一時的に NaN に置き換えます。

import numpy as np
cc_apps = cc_apps.replace('?', np.NaN)

print(cc_apps.tail(17))
      0      1       2  3  4   5   6      7  8  9   10 11 12     13   14 15
673  NaN  29.50   2.000  y  p   e   h  2.000  f  f   0  f  g  00256   17  -
674    a  37.33   2.500  u  g   i   h  0.210  f  f   0  f  g  00260  246  -
675    a  41.58   1.040  u  g  aa   v  0.665  f  f   0  f  g  00240  237  -
676    a  30.58  10.665  u  g   q   h  0.085  f  t  12  t  g  00129    3  -
677    b  19.42   7.250  u  g   m   v  0.040  f  t   1  f  g  00100    1  -
678    a  17.92  10.210  u  g  ff  ff  0.000  f  f   0  f  g  00000   50  -
679    a  20.08   1.250  u  g   c   v  0.000  f  f   0  f  g  00000    0  -
680    b  19.50   0.290  u  g   k   v  0.290  f  f   0  f  g  00280  364  -
681    b  27.83   1.000  y  p   d   h  3.000  f  f   0  f  g  00176  537  -
682    b  17.08   3.290  u  g   i   v  0.335  f  f   0  t  g  00140    2  -
683    b  36.42   0.750  y  p   d   v  0.585  f  f   0  f  g  00240    3  -
684    b  40.58   3.290  u  g   m   v  3.500  f  f   0  t  s  00400    0  -
685    b  21.08  10.085  y  p   e   h  1.250  f  f   0  f  g  00260    0  -
686    a  22.67   0.750  u  g   c   v  2.000  f  t   2  t  g  00200  394  -
687    a  25.25  13.500  y  p  ff  ff  2.000  f  t   1  t  g  00200    1  -
688    b  17.92   0.205  u  g  aa   v  0.040  f  f   0  f  g  00280  750  -
689    b  35.00   3.375  u  g   c   h  8.290  f  f   0  t  g  00000    0  -

欠損値の処理 2¶

すべての疑問符を NaN に置き換えました。これは、次に実行する欠損値の処理に役立ちます。

ここで生じる重要な疑問は、なぜ欠損値をそれほど重要視するのか ということです。

無視できない理由として:

  • 欠損値を無視すると、機械学習モデルのパフォーマンスに大きな影響を与える可能性があります。
  • 欠損値を無視すると、機械学習モデルはトレーニングに役立つ可能性のあるデータセットに関する情報を見逃してしまう可能性があります。
  • そして、線形判別分析のように欠損値を暗黙的に処理できないモデルも多くあります。

したがって、この問題を回避するために、平均代入と呼ばれる戦略を使用して欠損値を代入します。

import warnings
warnings.filterwarnings("ignore", category=FutureWarning)

cc_apps.fillna(np.NaN, inplace=True)

np.mean(cc_apps, axis=0)

cc_apps.tail(17)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
673 NaN 29.50 2.000 y p e h 2.000 f f 0 f g 00256 17 -
674 a 37.33 2.500 u g i h 0.210 f f 0 f g 00260 246 -
675 a 41.58 1.040 u g aa v 0.665 f f 0 f g 00240 237 -
676 a 30.58 10.665 u g q h 0.085 f t 12 t g 00129 3 -
677 b 19.42 7.250 u g m v 0.040 f t 1 f g 00100 1 -
678 a 17.92 10.210 u g ff ff 0.000 f f 0 f g 00000 50 -
679 a 20.08 1.250 u g c v 0.000 f f 0 f g 00000 0 -
680 b 19.50 0.290 u g k v 0.290 f f 0 f g 00280 364 -
681 b 27.83 1.000 y p d h 3.000 f f 0 f g 00176 537 -
682 b 17.08 3.290 u g i v 0.335 f f 0 t g 00140 2 -
683 b 36.42 0.750 y p d v 0.585 f f 0 f g 00240 3 -
684 b 40.58 3.290 u g m v 3.500 f f 0 t s 00400 0 -
685 b 21.08 10.085 y p e h 1.250 f f 0 f g 00260 0 -
686 a 22.67 0.750 u g c v 2.000 f t 2 t g 00200 394 -
687 a 25.25 13.500 y p ff ff 2.000 f t 1 t g 00200 1 -
688 b 17.92 0.205 u g aa v 0.040 f f 0 f g 00280 750 -
689 b 35.00 3.375 u g c h 8.290 f f 0 t g 00000 0 -

欠損値の処理 3¶

数値列に存在する欠損値を正常に処理しました。列 0、1、3、4、5、6、および 13 には、代入される欠損値がまだいくつかあります。
これらの列にはすべて非数値データが含まれているため、ここでは平均代入戦略が機能しません。これには別の方法が必要です。

これらの欠損値を、それぞれの列に存在する最も頻度の高い値で代入します。

  • cc_apps の各カラムをループ処理します
  • 列がオブジェクト型かどうかを確認します
  • オブジェクト型であれば最も頻度の高い値を代入する
  • データセット内の NaN の数を数え、その数を出力して確認
for col in cc_apps:
    if cc_apps[col].dtypes == 'object':
        cc_apps = cc_apps.fillna(cc_apps[col].value_counts().index[0])

cc_apps[col].isnull().sum()
0

Nan値が0になったことが確認できました。

4. データの分析¶

データの前処理 1¶

欠損値が正常に処理されるようになりました。

機械学習モデルの構築の前に、小規模ではあるが重要なデータの前処理がまだ必要です。これらの残りの前処理ステップを 3 つの主要なタスクに分割します。

  1. 数値以外のデータを数値に変換
  2. データをトレーニング セットとテスト セットに分割
  3. 特徴値を均一の範囲にスケール

まず、すべての非数値を数値に変換します。これを行うのは、計算が高速化されるだけでなく、多くの機械学習モデル (XGBoost など) (特に scikit-learn を使用して開発されたモデル) ではデータが厳密な数値形式である必要があるためです。これを行うには、ラベル エンコーディング と呼ばれる手法を使用します。

  • LabelEncoder のインポート
  • LabelEncoder を le としてインスタンス化する
  • 各カラムのすべての値を反復処理し、 dtype を抽出
  • dtype がオブジェクトかどうかを比較します
  • LabelEncoder を使用して数値変換を行う
from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()

for col in cc_apps.columns.to_numpy():
    if cc_apps[col].dtypes == 'object':
        cc_apps[col] = le.fit_transform(cc_apps[col])
cc_apps.head()
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 156 0.000 2 1 13 8 1.25 1 1 1 0 0 68 0 0
1 0 328 4.460 2 1 11 4 3.04 1 1 6 0 0 11 560 0
2 0 89 0.500 2 1 11 4 1.50 1 0 0 0 0 96 824 0
3 1 125 1.540 2 1 13 8 3.75 1 1 5 1 0 31 3 0
4 1 43 5.625 2 1 13 8 1.71 1 0 0 0 2 37 0 0

全てが数値に変化されたことがわかります。

データの前処理 2¶

データセットをトレーニング セットとテスト セットに分割する

次に、データをトレーニング セットとテスト セットに分割して、機械学習モデリングの 2 つの異なるフェーズ (トレーニングとテスト) に向けてデータを準備します。
理想的には、テスト データからの情報をトレーニング データのスケーリングに使用したり、機械学習モデルのトレーニング プロセスを指示するために使用したりすべきではありません。したがって、最初にデータを分割し、次にスケーリングを適用します。

また、DriversLicense や ZipCode などの特徴は、クレジット カードの承認を予測するデータセット内の他の特徴ほど重要ではありません。
最適な機能セットを備えた機械学習モデルを設計するには、それらを削除する必要があります。
データ サイエンスの文献では、これは 特徴選択 と呼ばれます。

  • train_test_split をインポートする
  • カラム 11 と 13 を削除し、DataFrame を NumPy 配列に変換
  • 特徴とラベルを別個の変数 X, y に分離する
  • トレーニング セットとテスト セットに分割する
from sklearn.model_selection import train_test_split

cc_apps_drop = cc_apps.drop([11, 13], axis=1)
cc_apps_drop.columns = range(cc_apps_drop.shape[1])

X = cc_apps_drop.drop([13] , axis=1)
y = cc_apps_drop[13]

X_train, X_test, y_train, y_test = train_test_split(X, y,
                                             test_size = 0.3, 
                                            random_state = 42
                                                   )

データの前処理 3¶

データは現在、トレーニング セットとテスト セットの 2 つの別々のセットに分割されています。
機械学習モデルをデータに適合させる前に、スケーリングという最後の前処理ステップが 1 つだけ残っています。

ここで、これらのスケール値が現実の世界で何を意味するのかを理解してみましょう。例として CreditScore を使用してみましょう。
個人の信用スコアは、信用履歴に基づいた信用度です。この数値が高いほど、その人は経済的に信頼できると考えられます。
したがって、すべての値を 0 ~ 1 の範囲に再スケーリングしているため、CreditScore 1 が最高になります。

  • MinMaxScaler のインポート
  • MinMaxScaler を scaler としてインスタンス化
  • インスタンスを使用して X_train と X_test を再スケーリング
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range = (0, 1))

rescaledX_train = scaler.fit_transform(X_train)
rescaledX_test = scaler.transform(X_test)

ロジスティック回帰モデルをトレーニングセットに適用する¶

基本的に、クレジット カードの申請が承認されるかどうかを予測することは、分類 タスクです。
UCI によると、データセットには、「承認」ステータスに対応するインスタンスよりも「拒否」ステータスに対応するインスタンスの方が多く含まれています。
具体的には、690 件の申請のうち、383 件 (55.5%) の申請が拒否され、307 件 (44.5%) の申請が承認されました。

これによりベンチマークが得られます。優れた機械学習モデルは、これらの統計に関してアプリケーションのステータスを正確に予測できる必要があります。

どのモデルを選択すればよいでしょうか?

尋ねるべき質問は次のとおりです: クレジット カードの承認決定プロセスに影響を与える機能は相互に相関しているか?

相関関係を測定することはできますが、次の直観に頼ることになります。
今のところ、それらは確かに相関しています。この相関関係により、このような場合には一般化線形モデルが適切に機能するという事実を利用します。
ロジスティック回帰モデル (一般化線形モデル) を使用して機械学習モデリングを開始しまします。

  • ロジスティック回帰のインポート
  • デフォルトのパラメータ値を使用して LogisticRegression 分類子をインスタンス化する
  • logreg をトレーニングセットに適合させる
from sklearn.linear_model import LogisticRegression

logreg = LogisticRegression()

logreg.fit(rescaledX_train, y_train)
LogisticRegression()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
LogisticRegression()

予測とパフォーマンスの評価¶

モデルはどれくらいうまく機能するのでしょうか?

次に、分類精度 に関してテスト セットでモデルを評価します。
ただし、モデルの 混同マトリックス も見ていきます。
クレジット カードの申請を予測する場合、機械学習モデルが、当初拒否された申請の承認ステータスを拒否されるかどうかを予測できるかどうかを確認することも同様に重要です。
この点でモデルのパフォーマンスが低い場合、承認されるべきアプリケーションが承認されてしまう可能性があります。
混乱マトリックスは、モデルのパフォーマンスをこれらの側面から見るのに役立ちます。

  • 混乱行列をインポート
  • logreg を使用してテスト セットからインスタンスを予測し、それを保存
  • logreg モデルの精度スコアを取得して出力
  • logreg モデルの混乱マトリックスを出力
from sklearn.metrics import confusion_matrix

y_pred = logreg.predict(rescaledX_test)


print("ロジスティック回帰の精度 test: ", logreg.score(rescaledX_test, y_test))
print("ロジスティック回帰の精度 train: ", logreg.score(rescaledX_train, y_train))

print(confusion_matrix(y_test, y_pred))
ロジスティック回帰の精度 test:  0.8405797101449275
ロジスティック回帰の精度 train:  0.8716356107660456
[[87 10]
 [23 87]]

グリッド検索とモデルのパフォーマンスの向上¶

ロジスティック回帰モデルは84%、サポートベクターマシンは85% の精度スコアを得ることができました。

混乱マトリックスの場合、最初の行の最初の要素は真の陰性を示し、モデルによって正しく予測された否定的なインスタンス (拒否されたアプリケーション) の数を意味します。
また、2 行目の最後の要素は、モデルによって正しく予測された陽性インスタンス (承認されたアプリケーション) の数を意味する真陽性を示します。

もっと改善できるかどうか見てみましょう。
モデル パラメーターの グリッド検索 を実行して、クレジット カードの承認を予測するモデルの能力を向上させることができます。

scikit-learn のロジスティック回帰の実装 はさまざまなハイパーパラメータで構成されていますが次の 2 つについてグリッド検索を行います。

  • tol
  • max_iter
  • GridSearchCV のインポート
  • tol と max_iter の値のグリッドを定義する
  • tol と max_iter がキーで、その値のリストが対応するバリューの辞書を作成
from sklearn.model_selection import GridSearchCV

C = [0.1, 1, 10]
tol = [0.01, 0.001, 0.0001]
max_iter = [100, 150, 200, 300, 400]

param_grid = dict(C = C, tol=tol, max_iter=max_iter)

5. 最高のパフォーマンスのモデルを見つける¶

ハイパーパラメータ値のグリッドを定義し、それらを GridSearchCV() がパラメータの 1 つとして期待する単一の辞書形式に変換しました。
次に、グリッド検索を開始して、どの値が最もパフォーマンスが高いかを確認します。

持っているすべてのデータを使用して、以前の logreg モデルを使用して GridSearchCV() をインスタンス化します。   トレーニング セットとテスト セットを別々に渡す代わりに、X (スケーリングされたバージョン) と y を提供します。   また、GridSearchCV() に 5 つの分割の 相互検証 を実行するように指示します。

  • 必要なパラメータを使用して GridSearchCV をインスタンス化
  • スケーラーを使用して X を再スケールし、それを rescaledX に割り当て
  • データをgrid_modelに適合させる
  • 結果を出力
rescaledX = scaler.fit_transform(X_train)

grid_model = GridSearchCV(estimator=logreg, param_grid=param_grid, cv=5)

grid_model_result = grid_model.fit(rescaledX, y_train)

print("最高値: %f 使用パラメータ %s" % (grid_model_result.best_score_, grid_model_result.best_params_))
最高値: 0.867397 使用パラメータ {'C': 0.1, 'max_iter': 100, 'tol': 0.01}

ロジスティック回帰では86.7%がベストスコアとそれぞれのパラメーターとなります。

SVC(サポートベクターマシン)の場合¶

from sklearn.svm import SVC

svc = SVC()
svc.fit(rescaledX_train, y_train)

y_pred_svc = svc.predict(rescaledX_test)

print("サポートベクターマシンの精度 test: ", svc.score(rescaledX_test, y_test))
print("サポートベクターマシンの精度 train: ", svc.score(rescaledX_train, y_train))

print(confusion_matrix(y_test, y_pred_svc))
サポートベクターマシンの精度 test:  0.8502415458937198
サポートベクターマシンの精度 train:  0.8861283643892339
[[85 12]
 [19 91]]
svc_params = {
    'C': [0.1, 1, 10],
    'kernel': ['linear', 'rbf', 'poly'],
    'gamma': ['scale', 'auto', 0.1, 1, 10],
    'coef0': [0.0, 0.1, 0.5],
    'degree': [2, 3, 4]
}
svc_grid_model = GridSearchCV(estimator=svc, param_grid=svc_params, cv=5)

svc_grid_model_result = svc_grid_model.fit(rescaledX, y_train)

print("最高値: %f 使用パラメータ %s" % (svc_grid_model_result.best_score_, svc_grid_model_result.best_params_))
最高値: 0.871521 使用パラメータ {'C': 0.1, 'coef0': 0.0, 'degree': 2, 'gamma': 1, 'kernel': 'rbf'}

RandomForestClassifier¶

from sklearn.ensemble import RandomForestClassifier

rf_model = RandomForestClassifier()
rf_model.fit(rescaledX_train, y_train)

y_pred_rf = rf_model.predict(rescaledX_test)

print("ランダムフォレストの精度 test: ", rf_model.score(rescaledX_test, y_test))
print("ランダムフォレストの精度 train: ", rf_model.score(rescaledX_train, y_train))

print(confusion_matrix(y_test, y_pred_svc))
ランダムフォレストの精度 test:  0.8695652173913043
ランダムフォレストの精度 train:  1.0
[[85 12]
 [19 91]]
rf_params = {
            'n_estimators': [10, 50, 100],
            'max_depth': [None, 10, 20],
            'min_samples_split': [2, 5, 10]
            }

rf_grid_model = GridSearchCV(estimator=rf_model, param_grid=rf_params, cv=5)

rf_grid_model_result = rf_grid_model.fit(rescaledX, y_train)

print("最高値: %f 使用パラメータ %s" % (rf_grid_model_result.best_score_, rf_grid_model_result.best_params_))
最高値: 0.873647 使用パラメータ {'max_depth': 20, 'min_samples_split': 5, 'n_estimators': 10}

4種類のスケーリングを検証し、更にロジスティック回帰と一緒にランダムフォレスト、リッジ回帰、ラッソ回帰、勾配ブースティング、サポートベクターマシンをれぞれの最適パラーメータで最適なものを探します。

  • モデルのインポート
  • スケーラー、パラメータを設定
  • 関数を意義
  • forループでスケーラーとモデルごとのパラメータをグリッドサーチをする
from sklearn.preprocessing import StandardScaler, MinMaxScaler, Normalizer, RobustScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import Ridge, Lasso
from sklearn.ensemble import GradientBoostingRegressor

スケーラー、モデル、パラメータを定義

scalers = [
    ('StandardScaler', StandardScaler()),
    ('MinMaxScaler', MinMaxScaler()),
    ('RobustScaler', RobustScaler()),
    ('Normalizer', Normalizer())
]

models_and_params = [
    {'model': LogisticRegression(),
        'params': {
            'C': [0.1, 1, 10],
            'tol': [0.01, 0.001, 0.0001],
            'max_iter': [100, 150, 200, 300]},
    },
    {'model': RandomForestClassifier(),
        'params': {
            'n_estimators': [10, 50, 100],
            'max_depth': [None, 10, 20],
            'min_samples_split': [2, 5, 10]},
    },
    {'model': Ridge(),
        'params': {'alpha': [0.01, 0.1, 1, 10]},
    },
    {'model': Lasso(),
        'params': {'alpha': [0.01, 0.1, 1, 10]},
    },
    {'model': GradientBoostingRegressor(),
        'params': {
            'n_estimators': [50, 100, 200],
            'learning_rate': [0.01, 0.1, 1.0],
            'max_depth': [3, 4, 5]},
    },
    {'model': SVC(),
        'params': {
            'C': [0.1, 1, 10],
            'kernel': ['linear', 'rbf', 'poly'],
            'gamma': ['scale', 0.1, 1],
            'degree': [2, 3, 4]}
   },
]

関数を定義

from concurrent.futures import ThreadPoolExecutor

def process_model_scales(scaler_name, scaler, model_info):
    model_name = model_info['model'].__class__.__name__
    param_grid = model_info['params']

    X_train_scaled = scaler.fit_transform(X_train)

    grid_search = GridSearchCV(estimator=model_info['model'], param_grid=param_grid, cv=5)
    result_grid_search = grid_search.fit(X_train_scaled, y_train)

    best_params = result_grid_search.best_params_
    best_score = result_grid_search.best_score_

    return {
        'Model': model_name,
        'Scaler': scaler_name,
        'Best Parameters': best_params,
        'Best Score': best_score
    }
model_scaler_combinations = []

with ThreadPoolExecutor() as executor:
    for scaler_name, scaler in scalers:
        for item in models_and_params:
            future = executor.submit(process_model_scales, scaler_name, scaler, item)
            model_scaler_combinations.append(future.result())
df_model_info = pd.DataFrame(model_scaler_combinations)

best_scalers = df_model_info.groupby('Model')['Best Score'].idxmax()

df_best_scalers = df_model_info.loc[best_scalers]

df_best_scalers.set_index('Model')
df_best_scalers.sort_values('Best Score', ascending= False)
Model Scaler Best Parameters Best Score
19 RandomForestClassifier Normalizer {'max_depth': 10, 'min_samples_split': 10, 'n_... 0.882002
11 SVC MinMaxScaler {'C': 0.1, 'degree': 2, 'gamma': 1, 'kernel': ... 0.871521
6 LogisticRegression MinMaxScaler {'C': 0.1, 'max_iter': 100, 'tol': 0.01} 0.867397
22 GradientBoostingRegressor Normalizer {'learning_rate': 0.01, 'max_depth': 3, 'n_est... 0.609969
8 Ridge MinMaxScaler {'alpha': 0.1} 0.573402
3 Lasso StandardScaler {'alpha': 0.01} 0.569103
for i in df_best_scalers.loc[19,:]:print(i)
RandomForestClassifier
Normalizer
{'max_depth': 10, 'min_samples_split': 10, 'n_estimators': 50}
0.8820017182130584

上データから

  • RandomForestClassifierモデルを使用し
  • Normalizerでスケーリング
  • パラメータの設定を{'max_depth': 10, 'min_samples_split': 10, 'n_estimators': 50}

にすると88.2%の精度になることがわかりました。

このクレジット カード予測機能を構築する際、スケーリング、ラベル エンコーディング、欠損値の代入など、最も広く知られている前処理ステップのいくつかに取り組みました。
ある人のクレジット カードの申請が承認されるか、その人に関する情報が与えられないかを予測するための機械学習を完了しました。