- 仮説や前処理した結果から得られた知見
- データサイエンスの知識に基づく知見
- ドメイン知識に基づく知見
などを用いて、新たな説明変数を構築することです。
説明変数が増えることにより、
機械学習のモデルとしては精度向上に貢献する強力なツールとなりえますが、
その一方で人為的に説明変数を増やすことにより過学習にも陥りやすく、
特徴量エンジニアリングは諸刃の剣とも言える手法です。
支払い状況から特徴量作成
支払い状況を見て、常に支払いが滞っているクライアントは、
今後も支払いが滞る可能性が高いとの仮説があるとます。
この仮説に基づき、PAY_
系の指標をすべて合計して、
値が多いクライアントはデフォルトの可能性が高いクライアントである
と仮定してクライアントに対してラベル付けをしましょう!!
data['pay_total'] = (data.PAY_1 + data.PAY_2 + data.PAY_3 + data.PAY_4 + data.PAY_5 + data.PAY_6)
data.head(10)
新たに作成した列を可視化
sns.countplot('pay_total',data=data)
sns.boxplot(x = data['pay_total'])
data['pay_total'].describe()
count 1000.000000 mean 1.724000 std 3.928264 min 0.000000 25% 0.000000 50% 0.000000 75% 2.000000 max 33.000000 Name: pay_total, dtype: float64
さらに、risk_cat
列を作成する。
今回は箱ひげ図を参考に
- 最小値から中央値までを
low
- 中央値以降~外れ値を除く最大値までを
medium
- 外れ値を
high
としました。
data['risk_cat'] = pd.cut(data.pay_total, [-1,0,5,36], labels=["low","medium","high"])
データ状況から特徴量作成
PAY_X
,BILL_AMTX
,PAY_AMTX
のときの値が全て0であれば、
クレジットカードの支払いには影響しないクライアントにだと考えられます。
このクライアントに対しても新たなclientX
の特徴量を作成しましょう!!
payNumList = ['PAY_' + str(i+1) for i in range(6)]
billAmtNumList = ['BILL_AMT' + str(i+1) for i in range(6)]
payAmtNumList = ['PAY_AMT' + str(i+1) for i in range(6)]
clientNumList = ['client' + str(i+1) for i in range(6)]
clientNumList で、client1~6というコラムを作る
for payNum, billAmtNum, payAmtNum, clientNum
in zip(payNumList, billAmtNumList, payAmtNumList, clientNumList):
data[clientNum] = 1 data.clientNumだとダメ
data.loc[
(
(data[payNum]==0) & (data[billAmtNum]==0) & (data[payAmtNum]==0)),
clientNum] = 0
zipでindexを作る
まず、clientNum を1にする。
そして、data.loc[条件,clientNum] =0にする
そうすることで、条件(payNum,billAmtNum,payAmtNum==0)というのに一致するのが0となる、0 or 1の列を6つ作ることが出来る。
data.columns
Index(['LIMIT_BAL', 'SEX', 'EDUCATION', 'MARRIAGE', 'AGE', 'PAY_1', 'PAY_2', 'PAY_3', 'PAY_4', 'PAY_5', 'PAY_6', 'BILL_AMT1', 'BILL_AMT2', 'BILL_AMT3', 'BILL_AMT4', 'BILL_AMT5', 'BILL_AMT6', 'PAY_AMT1', 'PAY_AMT2', 'PAY_AMT3', 'PAY_AMT4', 'PAY_AMT5', 'PAY_AMT6', 'default.payment.next.month', 'pay_total', 'risk_cat', 'client1', 'client2', 'client3', 'client4', 'client5', 'client6'], dtype='object')
data
LIMIT_BAL | SEX | EDUCATION | MARRIAGE | AGE | PAY_1 | PAY_2 | PAY_3 | PAY_4 | PAY_5 | … | PAY_AMT6 | default.payment.next.month | pay_total | risk_cat | client1 | client2 | client3 | client4 | client5 | client6 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 20000.0 | 2 | 2 | 1 | 24 | 2 | 2 | 0 | 0 | 0 | … | 0 | 1 | 4 | medium | 1 | 1 | 1 | 0 | 0 | 0 |
1 | 120000.0 | 2 | 2 | 2 | 26 | 0 | 2 | 0 | 0 | 0 | … | 2000 | 1 | 4 | medium | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 90000.0 | 2 | 2 | 2 | 34 | 0 | 0 | 0 | 0 | 0 | … | 5000 | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 |
3 | 50000.0 | 2 | 2 | 1 | 37 | 0 | 0 | 0 | 0 | 0 | … | 1000 | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 |
4 | 50000.0 | 1 | 2 | 1 | 57 | 0 | 0 | 0 | 0 | 0 | … | 679 | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 |
… | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … |
995 | 200000.0 | 1 | 1 | 2 | 39 | 0 | 0 | 0 | 0 | 0 | … | 0 | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 0 |
996 | 140000.0 | 1 | 1 | 1 | 45 | 0 | 0 | 0 | 0 | 2 | … | 1495 | 0 | 4 | medium | 1 | 1 | 1 | 1 | 1 | 1 |
997 | 360000.0 | 1 | 1 | 1 | 38 | 1 | 0 | 0 | 0 | 0 | … | 0 | 1 | 1 | medium | 1 | 0 | 0 | 0 | 0 | 0 |
998 | 50000.0 | 2 | 2 | 2 | 23 | 0 | 0 | 0 | 0 | 0 | … | 18300 | 1 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 |
999 | 120000.0 | 1 | 2 | 2 | 25 | 2 | 2 | 0 | 0 | 0 | … | 2000 | 0 | 4 | medium | 1 | 1 | 1 | 1 | 1 | 1 |
ドメイン知識から特徴量作成
下記のリンク先の調査によると、
https://zuuonline.com/archives/183430
若年層(18~34)と中高年層(35over)を比較した場合
- 若年層は中高年層の2倍の割合で「支払いの遅れ」
- 若年層は中高年層の3倍の割合で「支払いの遅れの経験」
があることが分かった。
data['AGE'].describe()
count 1000.00000 mean 34.93800 std 9.22818 min 21.00000 25% 28.00000 50% 33.00000 75% 41.00000 max 75.00000 Name: AGE, dtype: float64
data['age_group'] = pd.cut(data.AGE, [21,34,79], labels=['young','middle_senior'])
data.head()
LIMIT_BAL | SEX | EDUCATION | MARRIAGE | AGE | PAY_1 | PAY_2 | PAY_3 | PAY_4 | PAY_5 | … | default.payment.next.month | pay_total | risk_cat | client1 | client2 | client3 | client4 | client5 | client6 | age_group | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 20000.0 | 2 | 2 | 1 | 24 | 2 | 2 | 0 | 0 | 0 | … | 1 | 4 | medium | 1 | 1 | 1 | 0 | 0 | 0 | young |
1 | 120000.0 | 2 | 2 | 2 | 26 | 0 | 2 | 0 | 0 | 0 | … | 1 | 4 | medium | 1 | 1 | 1 | 1 | 1 | 1 | young |
2 | 90000.0 | 2 | 2 | 2 | 34 | 0 | 0 | 0 | 0 | 0 | … | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 | young |
3 | 50000.0 | 2 | 2 | 1 | 37 | 0 | 0 | 0 | 0 | 0 | … | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 | middle_senior |
4 | 50000.0 | 1 | 2 | 1 | 57 | 0 | 0 | 0 | 0 | 0 | … | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 | middle_senior |
data[data['age_group'] == 'young'].head(10)
LIMIT_BAL | SEX | EDUCATION | MARRIAGE | AGE | PAY_1 | PAY_2 | PAY_3 | PAY_4 | PAY_5 | … | default.payment.next.month | pay_total | risk_cat | client1 | client2 | client3 | client4 | client5 | client6 | age_group | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 20000.0 | 2 | 2 | 1 | 24 | 2 | 2 | 0 | 0 | 0 | … | 1 | 4 | medium | 1 | 1 | 1 | 0 | 0 | 0 | young |
1 | 120000.0 | 2 | 2 | 2 | 26 | 0 | 2 | 0 | 0 | 0 | … | 1 | 4 | medium | 1 | 1 | 1 | 1 | 1 | 1 | young |
2 | 90000.0 | 2 | 2 | 2 | 34 | 0 | 0 | 0 | 0 | 0 | … | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 | young |
6 | 500000.0 | 1 | 1 | 2 | 29 | 0 | 0 | 0 | 0 | 0 | … | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 | young |
7 | 100000.0 | 2 | 2 | 2 | 23 | 0 | 0 | 0 | 0 | 0 | … | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 | young |
8 | 140000.0 | 2 | 3 | 1 | 28 | 0 | 0 | 2 | 0 | 0 | … | 0 | 2 | medium | 1 | 1 | 1 | 1 | 1 | 1 | young |
10 | 200000.0 | 2 | 3 | 2 | 34 | 0 | 0 | 2 | 0 | 0 | … | 0 | 2 | medium | 1 | 1 | 1 | 1 | 1 | 1 | young |
13 | 70000.0 | 1 | 2 | 2 | 30 | 1 | 2 | 2 | 0 | 0 | … | 1 | 7 | high | 1 | 1 | 1 | 1 | 1 | 1 | young |
14 | 250000.0 | 1 | 1 | 2 | 29 | 0 | 0 | 0 | 0 | 0 | … | 0 | 0 | low | 1 | 1 | 1 | 1 | 1 | 1 | young |
15 | 50000.0 | 2 | 3 | 3 | 23 | 1 | 2 | 0 | 0 | 0 | … | 0 | 3 | medium | 1 | 1 | 1 | 1 | 1 | 1 | young |
カテゴリカルデータのone-hot-encoding
多くの機械学習モデルではカテゴリカルデータをそのまま値として処理できないので、.get_dummies
を用いてone-hot-encoding
を行います。
【Point】.get_dummies
でdrop_first = True
を指定することで、多重共線性の回避ができます。
data.describe()
LIMIT_BAL | SEX | EDUCATION | MARRIAGE | AGE | PAY_1 | PAY_2 | PAY_3 | PAY_4 | PAY_5 | … | PAY_AMT5 | PAY_AMT6 | default.payment.next.month | pay_total | client1 | client2 | client3 | client4 | client5 | client6 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 | 1000.00000 | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 | … | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 |
mean | 167080.000000 | 1.591000 | 1.769000 | 1.614000 | 34.93800 | 0.370000 | 0.312000 | 0.321000 | 0.236000 | 0.234000 | … | 5330.393000 | 5102.291000 | 0.214000 | 1.724000 | 0.982000 | 0.928000 | 0.913000 | 0.902000 | 0.893000 | 0.870000 |
std | 130632.838668 | 0.491895 | 0.721221 | 0.530363 | 9.22818 | 0.842502 | 0.844612 | 0.868743 | 0.769998 | 0.744176 | … | 16820.512403 | 23669.363588 | 0.410332 | 3.928264 | 0.133018 | 0.258617 | 0.281976 | 0.297463 | 0.309268 | 0.336472 |
min | 10000.000000 | 1.000000 | 1.000000 | 1.000000 | 21.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | … | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
25% | 50000.000000 | 1.000000 | 1.000000 | 1.000000 | 28.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | … | 194.250000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
50% | 140000.000000 | 2.000000 | 2.000000 | 2.000000 | 33.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | … | 1304.500000 | 1274.000000 | 0.000000 | 0.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
75% | 240000.000000 | 2.000000 | 2.000000 | 2.000000 | 41.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | … | 3739.750000 | 3800.000000 | 0.000000 | 2.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
max | 700000.000000 | 2.000000 | 4.000000 | 3.000000 | 75.00000 | 8.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | … | 195599.000000 | 528666.000000 | 1.000000 | 33.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
payNumList = ['PAY_' + str(i+1) for i in range(6)]
dummyColList = ['SEX', 'EDUCATION', 'MARRIAGE'] + payNumList + ['age_group','risk_cat']
dummyColList →ただのカテゴリ変数のリストを作成
['SEX',
'EDUCATION',
'MARRIAGE',
'PAY_1',
'PAY_2',
'PAY_3',
'PAY_4',
'PAY_5',
'PAY_6',
'age_group',
'risk_cat']
fnData = pd.get_dummies(data,drop_first=True,columns=dummyColList)
fnData
LIMIT_BAL | AGE | BILL_AMT1 | BILL_AMT2 | BILL_AMT3 | BILL_AMT4 | BILL_AMT5 | BILL_AMT6 | PAY_AMT1 | PAY_AMT2 | … | PAY_5_5 | PAY_5_7 | PAY_6_2 | PAY_6_3 | PAY_6_4 | PAY_6_6 | PAY_6_7 | age_group_middle_senior | risk_cat_medium | risk_cat_high | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 20000.0 | 24 | 3913 | 3102 | 689.0 | 0 | 0 | 0 | 0 | 689 | … | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
1 | 120000.0 | 26 | 2682 | 1725 | 2682.0 | 3272 | 3455 | 3261 | 0 | 1000 | … | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
2 | 90000.0 | 34 | 29239 | 14027 | 13559.0 | 14331 | 14948 | 15549 | 1518 | 1500 | … | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3 | 50000.0 | 37 | 46990 | 48233 | 49291.0 | 28314 | 28959 | 29547 | 2000 | 2019 | … | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
4 | 50000.0 | 57 | 8617 | 5670 | 35835.0 | 20940 | 19146 | 19131 | 2000 | 36681 | … | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
… | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … |
995 | 200000.0 | 39 | -200 | -200 | -200.0 | 0 | 60800 | 0 | 0 | 0 | … | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
996 | 140000.0 | 45 | 39716 | 40799 | 41853.0 | 44452 | 45433 | 46383 | 1600 | 1600 | … | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
997 | 360000.0 | 38 | 0 | 0 | 0.0 | 0 | 0 | 0 | 0 | 0 | … | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
998 | 50000.0 | 23 | 780 | 0 | 780.0 | 390 | 390 | 500 | 0 | 780 | … | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
999 | 120000.0 | 25 | 113348 | 110119 | 111700.0 | 83858 | 86434 | 88802 | 0 | 5000 | … | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
1000 rows × 64 columns
columns=dummyColListでダミー変数を作り変数のリストを指定している。
コメント