コンペチュートリアル 前処理 機械学習

探索的データ分析 | PortoSeguro コンペ

投稿日:11月 28, 2019 更新日:

概要説明

本記事は、機械学習を始めて基本的な操作を覚え、次に精度を上げるために何をすればよいのか?という悩みを持つ方たちのために、機械学習のコンペサイトkaggleの練習問題をベースに事例を紹介していきたいと思います。

本記事では、Bert Carremansさんのノートブックを参考にしています。

このノートブックはPortoSeguroコンペのデータを理解することを目的としています。

コンペの説明

ブラジル最大の自動車および住宅所有者保険会社の1つであるPorto Seguroの事例です。
このコンペでは、保険加入者が翌年に自動車保険の請求を行う確率を予測するモデルの構築に挑戦します。

章立ては以下の構成となります。

  1. データの可視化
  2. メタデータの定義
  3. 記述統計
  4. 不均衡なクラスの処理
  5. データ品質チェック
  6. 探索的データの視覚化
  7. 特徴量エンジニアリング
  8. 特徴量選択
  9. 特徴量のスケーリング

パッケージの読み込み

データの読み込み

データについて

以下は、コンペのデータ説明の抜粋です。

  •  同一属性の特徴量にはind、reg、car、calcなどでタグ付けされている
  •  バイナリ変数にはbin、カテゴリ変数にはcatが特徴量名末尾に付与される
  •  これらの指定がない特徴量は、連続変数または順序変数のいずれかである
  •  -1の値は欠損値を示す
  •  target列は、保険契約者に対して申し立てが行われたかどうかを示す

まずは、この情報をデータで確認します。

idtargetps_ind_01ps_ind_02_catps_ind_03ps_ind_04_catps_ind_05_catps_ind_06_binps_ind_07_binps_ind_08_binps_ind_09_binps_ind_10_binps_ind_11_binps_ind_12_binps_ind_13_binps_ind_14ps_ind_15ps_ind_16_binps_ind_17_binps_ind_18_binps_reg_01ps_reg_02ps_reg_03ps_car_01_catps_car_02_catps_car_03_catps_car_04_catps_car_05_catps_car_06_catps_car_07_catps_car_08_catps_car_09_catps_car_10_catps_car_11_catps_car_11ps_car_12ps_car_13ps_car_14ps_car_15ps_calc_01ps_calc_02ps_calc_03ps_calc_04ps_calc_05ps_calc_06ps_calc_07ps_calc_08ps_calc_09ps_calc_10ps_calc_11ps_calc_12ps_calc_13ps_calc_14ps_calc_15_binps_calc_16_binps_calc_17_binps_calc_18_binps_calc_19_binps_calc_20_bin
07022510010000000110100.70.20.718070101-101410011220.4000000.8836790.3708103.6055510.60.50.23110110159158011001
1901170000100000030010.80.40.766078111-10-11111211930.3162280.6188170.3887162.4494900.30.10.321958173119011010
213054910001000000121000.00.0-1.00000071-10-11411216010.3162280.6415860.3472753.3166250.50.70.122918274277011010
31600120010000000081000.90.20.5809487100111113110410.3741660.5429490.2949582.0000000.60.90.124718422249000000
41700201010000000091000.70.60.840759111-10-11411218230.3160700.5658320.3651032.0000000.40.60.02263102123113000110

説明通りであることがわかります。
次は、trainデータのサイズを確認してみます。

train.shape

(595212, 59)

59列595,212行のテーブルとなっています。
重複についても念の為確認します。

(595212, 59)

重複はないようです。

(892816, 58)

testデータはターゲットデータがないため、trainデータと比べて列が1つ少ないです。

次に、データ型を確認します。

train.info()

データ型は、全て整数または浮動小数点数であることがわかります。 欠損値は-1に置き換えられるため、データセットにnull値はありません。

メタデータ

To facilitate the data management, we’ll store meta-information about the variables in a DataFrame. This will be helpful when we want to select specific variables for analysis, visualization, modeling, …

Concretely we will store:

  • role: input, ID, target
  • level: nominal, interval, ordinal, binary
  • keep: True or False
  • dtype: int, float, str

データ管理を容易にするために、変数に関するメタ情報をDataFrameに保存します。これは、分析、視覚化、モデリングなどの特定の変数を選択するときに役立ちます。

具体的には以下を保存します:

  •   role:input, id, target
  •   lebel:normal, nterval, ordinal, binary
  •   keep:True, False
  •   dtype:int, float, str
rolelevelkeepdtype
varname
ididnominalFalseint64
targettargetbinaryTrueint64
ps_ind_01inputordinalTrueint64
ps_ind_02_catinputnominalTrueint64
ps_ind_03inputordinalTrueint64
ps_ind_04_catinputnominalTrueint64
ps_ind_05_catinputnominalTrueint64
ps_ind_06_bininputbinaryTrueint64
ps_ind_07_bininputbinaryTrueint64
ps_ind_08_bininputbinaryTrueint64
ps_ind_09_bininputbinaryTrueint64
ps_ind_10_bininputbinaryTrueint64
ps_ind_11_bininputbinaryTrueint64
ps_ind_12_bininputbinaryTrueint64
ps_ind_13_bininputbinaryTrueint64
ps_ind_14inputordinalTrueint64
ps_ind_15inputordinalTrueint64
ps_ind_16_bininputbinaryTrueint64
ps_ind_17_bininputbinaryTrueint64
ps_ind_18_bininputbinaryTrueint64
ps_reg_01inputintervalTruefloat64
ps_reg_02inputintervalTruefloat64
ps_reg_03inputintervalTruefloat64
ps_car_01_catinputnominalTrueint64
ps_car_02_catinputnominalTrueint64
ps_car_03_catinputnominalTrueint64
ps_car_04_catinputnominalTrueint64
ps_car_05_catinputnominalTrueint64
ps_car_06_catinputnominalTrueint64
ps_car_07_catinputnominalTrueint64
ps_car_08_catinputnominalTrueint64
ps_car_09_catinputnominalTrueint64
ps_car_10_catinputnominalTrueint64
ps_car_11_catinputnominalTrueint64
ps_car_11inputordinalTrueint64
ps_car_12inputintervalTruefloat64
ps_car_13inputintervalTruefloat64
ps_car_14inputintervalTruefloat64
ps_car_15inputintervalTruefloat64
ps_calc_01inputintervalTruefloat64
ps_calc_02inputintervalTruefloat64
ps_calc_03inputintervalTruefloat64
ps_calc_04inputordinalTrueint64
ps_calc_05inputordinalTrueint64
ps_calc_06inputordinalTrueint64
ps_calc_07inputordinalTrueint64
ps_calc_08inputordinalTrueint64
ps_calc_09inputordinalTrueint64
ps_calc_10inputordinalTrueint64
ps_calc_11inputordinalTrueint64
ps_calc_12inputordinalTrueint64
ps_calc_13inputordinalTrueint64
ps_calc_14inputordinalTrueint64
ps_calc_15_bininputbinaryTrueint64
ps_calc_16_bininputbinaryTrueint64
ps_calc_17_bininputbinaryTrueint64
ps_calc_18_bininputbinaryTrueint64
ps_calc_19_bininputbinaryTrueint64
ps_calc_20_bininputbinaryTrueint64

たとえば、normalデータを抽出する場合

Index([‘ps_ind_02_cat’, ‘ps_ind_04_cat’, ‘ps_ind_05_cat’, ‘ps_car_01_cat’, ‘ps_car_02_cat’, ‘ps_car_03_cat’, ‘ps_car_04_cat’, ‘ps_car_05_cat’, ‘ps_car_06_cat’, ‘ps_car_07_cat’, ‘ps_car_08_cat’, ‘ps_car_09_cat’, ‘ps_car_10_cat’, ‘ps_car_11_cat’], dtype=’object’, name=’varname’)

roleとlevelごとの変数の数を集計すると

rolelevelcount
0idnominal1
1inputbinary17
2inputinterval10
3inputnominal14
4inputordinal16
5targetbinary1

記述統計

describeを使えば各データの記述統計を容易に集計することができます。
ただし、カテゴリ変数とid変数の平均、標準、…を計算することはあまり意味がないので、
データ型ごとに記述統計を確認することにします。

間隔変数


ps_reg_01
ps_reg_02ps_reg_03ps_car_12ps_car_13ps_car_14ps_car_15ps_calc_01ps_calc_02ps_calc_03
count595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000
mean0.6109910.4391840.5511020.3799450.8132650.2762563.0658990.4497560.4495890.449849
std0.2876430.4042640.7935060.0583270.2245880.3571540.7313660.2871980.2868930.287153
min0.0000000.000000-1.000000-1.0000000.250619-1.0000000.0000000.0000000.0000000.000000
25%0.4000000.2000000.5250000.3162280.6708670.3331672.8284270.2000000.2000000.200000
50%0.7000000.3000000.7206770.3741660.7658110.3687823.3166250.5000000.4000000.500000
75%0.9000000.6000001.0000000.4000000.9061900.3964853.6055510.7000000.7000000.700000
max0.9000001.8000004.0379451.2649113.7206260.6363963.7416570.9000000.9000000.900000

reg変数

  • ps_reg_03のみに欠損値があります
  • データの範囲(最小から最大)は変数によって異なっているため、スケーリング(StandardScalerなど)の検討が必要です。

car変数

  • ps_car_12、ps_car_14には欠損値があります
  • データの範囲(最小から最大)は変数によって異なっているため、スケーリング(StandardScalerなど)の検討が必要です。

calc変数

  • 欠損値はありません
  • 最大値は0.9であるため、これは何らかの比率のようです
  • 3つの_calc変数はすべて非常に類似した分布を持っています

全体的に、間隔変数の範囲はかなり小さいことがわかります。データを匿名化するために、おそらく何らかの変換(logなど)がすでに適用されているのでしょうか?

順序変数

ps_ind_01ps_ind_03ps_ind_14ps_ind_15ps_car_11ps_calc_04ps_calc_05ps_calc_06ps_calc_07ps_calc_08ps_calc_09ps_calc_10ps_calc_11ps_calc_12ps_calc_13ps_calc_14
count595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000
mean1.9003784.4233180.0124517.2999222.3460722.3720811.8858867.6894453.0058239.2259042.3390348.4335905.4413821.4419182.8722887.539026
std1.9837892.6999020.1275453.5460420.8325481.1172191.1349271.3343121.4145641.4596721.2469492.9045972.3328711.2029631.6948872.746652
min0.0000000.0000000.0000000.000000-1.0000000.0000000.0000000.0000000.0000002.0000000.0000000.0000000.0000000.0000000.0000000.000000
25%0.0000002.0000000.0000005.0000002.0000002.0000001.0000007.0000002.0000008.0000001.0000006.0000004.0000001.0000002.0000006.000000
50%1.0000004.0000000.0000007.0000003.0000002.0000002.0000008.0000003.0000009.0000002.0000008.0000005.0000001.0000003.0000007.000000
75%3.0000006.0000000.00000010.0000003.0000003.0000003.0000009.0000004.00000010.0000003.00000010.0000007.0000002.0000004.0000009.000000
max7.00000011.0000004.00000013.0000003.0000005.0000006.00000010.0000009.00000012.0000007.00000025.00000019.00000010.00000013.00000023.000000
  • 欠損値があるのはps_car_11だけ
  • 各データの範囲が異なるためスケーリングの検討が必要です

バイナリ変数

targetps_ind_06_binps_ind_07_binps_ind_08_binps_ind_09_binps_ind_10_binps_ind_11_binps_ind_12_binps_ind_13_binps_ind_16_binps_ind_17_binps_ind_18_binps_calc_15_binps_calc_16_binps_calc_17_binps_calc_18_binps_calc_19_binps_calc_20_bin
count595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000595212.000000
mean0.0364480.3937420.2570330.1639210.1853040.0003730.0016920.0094390.0009480.6608230.1210810.1534460.1224270.6278400.5541820.2871820.3490240.153318
std0.1874010.4885790.4369980.3702050.3885440.0193090.0410970.0966930.0307680.4734300.3262220.3604170.3277790.4833810.4970560.4524470.4766620.360295
min0.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000
25%0.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000
50%0.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000001.0000000.0000000.0000000.0000001.0000001.0000000.0000000.0000000.000000
75%0.0000001.0000001.0000000.0000000.0000000.0000000.0000000.0000000.0000001.0000000.0000000.0000000.0000001.0000001.0000001.0000001.0000000.000000
max1.0000001.0000001.0000001.0000001.0000001.0000001.0000001.0000001.0000001.0000001.0000001.0000001.0000001.0000001.0000001.0000001.0000001.000000
  • targetデータの正例の比率は3.65%程度で非常に不均衡なデータとなっています
  • ほとんどのデータは負例のデータとなっています

不均衡データの取り扱い

前述したように、target = 1のレコードの割合は、target = 0よりもはるかに少ないです。
この場合、全てのデータをtraget=0と予測すれば、一見高精度なモデルができたように見えてしまいます。
この問題に対処する方法は以下の2つです。

  • target = 1 レコードのオーバーサンプリング
  • target = 0 レコードのアンダーサンプリング

もちろん、対処法は他にも多数存在します。必要に応じてMachineLearningMastery.com)を参考にしてください。
今回はtrainセットがある程度のデータ数があるため、アンダーサンプリングを採用します。

Rate to undersample records with target=0: 0.34043569687437886 Number of records with target=0 after undersampling: 195246

count 216940.000000 mean 0.100000 std 0.300001 min 0.000000 25% 0.000000 50% 0.000000 75% 0.000000 max 1.000000 Name: target, dtype: float64

アンダーサンプリングにより、確かに正例の比率が10%になっています。

データのクオリティチェック

欠損値の処理

データの仕様により-1が欠損値となっています。

Variable ps_ind_02_cat has 103 records (0.05%) with missing values Variable ps_ind_04_cat has 51 records (0.02%) with missing values Variable ps_ind_05_cat has 2256 records (1.04%) with missing values Variable ps_reg_03 has 38580 records (17.78%) with missing values Variable ps_car_01_cat has 62 records (0.03%) with missing values Variable ps_car_02_cat has 2 records (0.00%) with missing values Variable ps_car_03_cat has 148367 records (68.39%) with missing values Variable ps_car_05_cat has 96026 records (44.26%) with missing values Variable ps_car_07_cat has 4431 records (2.04%) with missing values Variable ps_car_09_cat has 230 records (0.11%) with missing values Variable ps_car_11 has 1 records (0.00%) with missing values Variable ps_car_14 has 15726 records (7.25%) with missing values In total, there are 12 variables with missing values

この出力結果を踏まえて、以下の処理を行います。

  • ps_car_03_cat and ps_car_05_cat: 欠損値が多数存在するので、この二つの変数は削除します
  • 欠損値を持つ他のカテゴリ変数については、欠損値を-1のままにしておく
  • ps_reg_03 約18%の欠損値がります。これは平均値で置き換えます
  • ps_car_11 1レコードだけ欠損値が存在します。これは最頻値で置き換えます
  • ps_car_14 役7%欠損値があります。これは平均値で置き換えます

カテゴリ変数の確認

カテゴリ変数内のカテゴリ数が多い場合、ダミー変数を作成すると多数の特徴量ができてしまうため、 事前に確認を行い、必要に応じて処理をおこないます。

Variable ps_ind_02_cat has 5 distinct values Variable ps_ind_04_cat has 3 distinct values Variable ps_ind_05_cat has 8 distinct values Variable ps_car_01_cat has 13 distinct values Variable ps_car_02_cat has 3 distinct values Variable ps_car_04_cat has 10 distinct values Variable ps_car_06_cat has 18 distinct values Variable ps_car_07_cat has 3 distinct values Variable ps_car_08_cat has 2 distinct values Variable ps_car_09_cat has 6 distinct values Variable ps_car_10_cat has 3 distinct values Variable ps_car_11_cat has 104 distinct values

ps_car_11_cat:この変数は多くのカテゴリが存在します
処理方法:このカテゴリ数の問題は、oliverの手法を元に処理を行なっています。 この内容については、次回の記事にて紹介することとして、割愛します。

データ探索

カテゴリカル変数

カテゴリ変数とtarget=1の割合を見ていきます。

出力は省略

出力は省略

欠損値のある変数のグラフを見ると、欠損値は保険請求をする確率が他のカテゴリと比較して、
はるかに高いことがわかります。よって、欠損値は最頻値などで置き換えるのではなく、
そのまま一つのカテゴリとして保持する方が良さそうです。

間隔変数

変数間の相関を確認します。
可視化には、ヒートマップ使用します。

参考)
https://data-bunseki.com/2019/06/20/python-%E7%9B%B8%E9%96%A2%E8%A1%8C%E5%88%97correlation_matrix/

以下の変数間に強い相関が確認できます

  • ps_reg_02 / ps_reg_03 (0.7)
  • ps_car_12 / ps_car13 (0.67)
  • ps_car_12 / ps_car14 (0.58)
  • ps_car_13 / ps_car15 (0.67)

ヒートマップで強い相関が確認できた変数に関して、 ペアプロットを使用して、変数間の関係を視覚化します。 注:プロセスを高速化するために、データはサンプリングします。

ps_reg_02 / ps_reg_03

グラフから線形関係が確認できます。 target = 0とtarget = 1で 回帰直線に大きな違いがないこともわかります。

ps_car_12 / ps_car_13

ps_car_12 / ps_car_14

ps_car_13 / ps_car_15

これらの変数から線形の相関が確認できるため、PCAを用いて次元圧縮を行います。
ただし、相関変数の数はかなり少ないので、モデルの負荷となることに注意してください。

順序変数の相関

順序変数については、目立った相関関係は見られませんでした。

特徴量エンジニアリング

ダミー変数か

カテゴリ変数の値に数字的意味はありません。
(たとえば、カテゴリ2はカテゴリ1の値の2倍ではありません。)
したがって、ダミー変数として数値的意味を除去します。

Before dummification we have 57 variables in train

After dummification we have 109 variables in train

特徴量エンジニアリング

ダミー変数か

カテゴリ変数の値に数字的意味はありません。
(たとえば、カテゴリ2はカテゴリ1の値の2倍ではありません。)
したがって、ダミー変数として数値的意味を除去します。

ダミー変数化により、52の変数が追加されました。

交互作用変数の作成

Before creating interactions we have 109 variables in train After creating interactions we have 164 variables in train

交互作用特徴量とは、特徴量A × 特徴量Bのように複数の特徴量の積で作られる特徴量です。
2つ以上の要因が考えられる時、要因が組み合わさった時にだけ現れる作用のことを交互作用と言います。
これにより、変数の組み合わせの効果を持つ特徴量を作ることができます。

特徴量選択

情報の少ない特徴量の削除

SklearnのVarianceThresholdを使って、
情報少ない(分散がまったくないか、非常に低い)特徴量を削除します。
ここでは、分散が0.1以下の特徴量を削除します。

28 variables have too low variance. These variables are [‘ps_ind_10_bin’, ‘ps_ind_11_bin’, ‘ps_ind_12_bin’, ‘ps_ind_13_bin’, ‘ps_car_12’, ‘ps_car_14’, ‘ps_car_11_cat_te’, ‘ps_ind_05_cat_2’, ‘ps_ind_05_cat_5’, ‘ps_car_01_cat_1’, ‘ps_car_01_cat_2’, ‘ps_car_04_cat_3’, ‘ps_car_04_cat_4’, ‘ps_car_04_cat_5’, ‘ps_car_04_cat_6’, ‘ps_car_04_cat_7’, ‘ps_car_06_cat_2’, ‘ps_car_06_cat_5’, ‘ps_car_06_cat_8’, ‘ps_car_06_cat_12’, ‘ps_car_06_cat_16’, ‘ps_car_06_cat_17’, ‘ps_car_09_cat_4’, ‘ps_car_10_cat_1’, ‘ps_car_10_cat_2’, ‘ps_car_12^2’, ‘ps_car_12 ps_car_14’, ‘ps_car_14^2’]

分散0.1以下の特徴量とすると、多くの特徴量が落とされます。
しかし、これにより処理時間の短縮が期待できます。

また、Sklearnには他の特徴量選択の方法もあります。
その1つがSelectFromModelです。
このメソッドでは、別の分類子に最適な機能を選択させ、
これらを続行します。
以下に、ランダムフォレストでそれを行う方法を示します。

ランダムフォレストで特徴量を選択する方法

ランダムフォレストの重要度を使って特徴量を選択します。
SklearnのSelectFromModelを使用すると、保持する変数の数を指定できます。
機能の重要度のレベルに手動でしきい値を設定できます。
ただし、単純に上位50%の変数を選択します。

SelectFromModelを使用すると、使用する特徴量の重要度のしきい値を指定できます。 get_supportメソッドを使用すると、データ内の変数の数を制限できます。

Feature scaling

前述のように、trainデータにStadardScalerを適用します。これを行うと、いくつかの分類器の精度が向上します。

scaler = StandardScaler()
scaler.fit_transform(train.drop([‘target’], axis=1))

array([[-0.45941104, -1.26665356, 1.05087653, …, -0.72553616, -1.01071913, -1.06173767], [ 1.55538958, 0.95034274, -0.63847299, …, -1.06120876, -1.01071913, 0.27907892], [ 1.05168943, -0.52765479, -0.92003125, …, 1.95984463, -0.56215309, -1.02449277], …, [-0.9631112 , 0.58084336, 0.48776003, …, -0.46445747, 0.18545696, 0.27907892], [-0.9631112 , -0.89715418, -1.48314775, …, -0.91202093, -0.41263108, 0.27907892], [-0.45941104, -1.26665356, 1.61399304, …, 0.28148164, -0.11358706, -0.72653353]])

-コンペチュートリアル, 前処理, 機械学習

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

no image

kaggle:House Price チュートリアル(EDA探索的データ解析)

Contents1 概要説明1.1 データ探索の流れ2 ライブラリインポート3 データの読み込み4 データ項目からの考察5 SalePriceの分析5.1 ヒストグラムで分布の可視化5.2 数値変数と …

no image

タイタニック生存者予測~ランダムフォレスト~

有名なタイタニックのデータを使って、RandamForestを使って生存者を予測します。 Contents0.1 前処理について0.2 モデル選定について 0.2.1 ロジスティック回帰0.2.2 S …

no image

ハイパーパラメータの調整(分類器)

分類問題用にk-NN、SVM、ランダムフォレストの3つの手法及び各手法のハイパーパラメータを最適化するランダムサーチ、グリッドサーチのサンプルスクリプトです。 Contents1 データセット作成1. …

no image

python/pandas/DataFrame/欠損値確認

データフレーム内の値がNoneまたはNAかどうかを確認する。 ※isnullとisnaの機能は同じ。isnullはisnaの別名なのでisnaが推奨 Contents1 メソッド2 データの準備3 p …

no image

機械学習スタッキング例

汎化性能を上げるためkaggleでよく利用されている、スタッキングの実行例をメモしておきます。 スタッキングとは、単一の学習器をそのまま使うのではなく、複数の学習きを組み合わせることで、過学習を防ぎ予 …