Fearuture Selection with Information Value

Feature Selection에 Information Value를 이용해보자.

Information Value를 이용한 방법


Kaggle이나 데이터 분석을 하다보면 성능을 높이기 위해 여러가지 feature들을 만들어낸다. 그런데 feature를 무조건 많이 만든다고 성능이 올라갈까? 아니다. target에 대한 영향력이 큰 feature들이어야 성능에 영향을 줄 수 있을 것이다. 그렇다면 중요한 건, 만들어낸 feature들을 어떻게 평가할 것인가이다.

Kaggle에서 Feature Selection 하는 방법들을 보면 gbm모델들의 Feature Importance를 이용하거나 DecisionTree나 RandomForest의 Classifier 객체의 feature_importances_ 메서드를 활용해 Feature Importance를 구해서 비교하는 모습들이 자주 보인다.

하지만 또 다른 방법으로, Information Value를 이용한 Feature Selection을 소개해보고자 한다.

1. Information Value (정보 가치)

모델에서 변수의 사용유무를 판단하는 feature selection에서 유용한 방법이다. 주로 모델을 학습하기전 첫 단계에서 변수들을 제거하는 데 사용한다. 최종 모델에서는 대략 10개 내외의 변수를 사용하도록 한다(여러개 만들어 보고 비교해보는 것이 좋다). IV와 WOE 신용채무능력이 가능한(good) 고객과 불가능한(bad) 고객을 예측하는 로지스틱 회귀 모델링과 밀접한 관계가 있다. 신용 정보 관련분야에서는 good customer는 부채를 갚을 수 있는 고객, bad customer는 부채를 갚을 수 없는 고객을 뜻한다. 일반적으로 이야기할 때는 good customer는 non-events를 의미하고 bad customer는 events를 의미한다.

신용 관련 분야

$${WOE} = ln{\frac{\text{distribution of good}}{\text{distribution of bad}}}$$

$${IV} = \sum{(\text{WOE} \times (\text{distribution of good} - \text{distribution of bad}))}$$

일반적

$${WOE} = ln{\frac{\text{distribution of non-events}}{\text{distribution of events}}}$$

$${IV} = \sum{(\text{WOE} \times (\text{distribution of non-events} - \text{distribution of events}))}$$

  • Information Value 값의 의미
Information Value
예측력
0 to 0.02
무의미
0.02 to 0.1
낮은 예측
0.1 to 0.3
중간 예측
0.3 to 0.5
강한 예측
0.5 to 1
너무 강한 예측(의심되는 수치)

Information Value를 통해서 ‘이 feature를 꼭 사용해야하나?’에 대해 어느정도 답을 내릴 수 있다.

Information Value가 0.5~1.0인 구간을 보면, 강한 예측이지만 의심되는 수치라고 되어있다. 처음보면 이게 무슨 의미인지 잘 이해가 안될 것이다. ‘너무 예측을 잘하는데 수치를 의심하라고?’

하지만 잘 생각해보자. IV는 WOE를 활용한다. WOE는 good과 bad의 분포를 이용하는데, 데이터가 good으로 쏠려있을 경우 WOE는 무조건 잘 나올 수 밖에 없고, 이에 따라 IV값도 잘 나오게 된다.

따라서, IV의 값을 볼 때는 데이터가 어떻게 되어있는지 먼저 살펴보는 게 중요하다.

2. German Credit Data 이용해보기

1
2
path = 'https://archive.ics.uci.edu/ml/machine-learning-databases/statlog/german/german.data'
dataset = pd.read_csv(path, delimiter=' ', header=None)

Column이 제대로 되어있지 않기 때문에 노가다로 넣어준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
COL = [
'Status_of_existing_checking_account',
'Duration_in_month',
'Credit_history',
'Purpose',
'Credit_amount',
'Savings_account_bonds',
'Present_employment_since',
'Installment_rate_in_percentage_of_disposable_income',
'Personal_status_and_sex',
'Other_debtors_guarantors',
'Present_residence_since',
'Property',
'Age_in_years',
'Other_installment_plans',
'Housing',
'Number_of_existing_credits_at_this_bank',
'Job',
'Number_of_people_being_liable_to_provide_maintenance_for',
'Telephone',
'foreign_worker',
'Target'
]

Target값을 0, 1로 만들어준다.

1
dataset['Target'] = dataset['Target'] - 1

Information Value를 구하는 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
max_bin = 10  # 전체 데이터의 예측력에 해를 가하지 않는 한에서 구간을 테스트하였습니다. 통상적으로 10개로 나눔, 15개 20개 다 나눠보고
# 값이 잘나오는 bin을 선택함

def calc_iv(df, col, label, max_bin = max_bin):
"""IV helper function"""
bin_df = df[[col, label]].copy()
# Categorical column
if bin_df[col].dtype == 'object':
bin_df = bin_df.groupby(col)[label].agg(['count', 'sum'])
# Numerical column
else:
bin_df.loc[:, 'bins'] = pd.qcut(bin_df[col].rank(method='first'), max_bin)
# bin_df.loc[:, 'bins'] = pd.cut(bin_df[col], max_bin)
bin_df = bin_df.groupby('bins')[label].agg(['count', 'sum'])

bin_df.columns = ['total', 'abuse']
bin_df['normal'] = bin_df['total'] - bin_df['abuse']
bin_df['normal_dist'] = bin_df['normal'] / sum(bin_df['normal'])
bin_df['abuse_dist'] = bin_df['abuse'] / sum(bin_df['abuse'])
bin_df['woe'] = np.log(bin_df['normal_dist'] / bin_df['abuse_dist'])
bin_df['iv'] = bin_df['woe'] * (bin_df['normal_dist'] - bin_df['abuse_dist'])

bin_df.replace([np.inf, -np.inf], 0, inplace=True)
bin_df = bin_df[bin_df['total'] > 0]
iv_val = sum(filter(lambda x: x != float('inf'), bin_df['iv']))

return bin_df, col, iv_val
1
2
ch_df, ch, ch_i_val = calc_iv(dataset,'Credit_history', 'Target')
ch_df

| |total |abuse |normal |normal_dist |abuse_dist |woe |iv|
|:—-:||:—-:||:—-:||:—-:||:—-:||:—-:||:—-:||:—-:|
|Credit_history||||||||
|A30|40|25| 15|0.021429|0.083333|-1.358123|0.084074|
|A31|49|28| 21|0.030000|0.093333|-1.134980|0.071882|
|A32|530|169|361|0.515714|0.563333|-0.088319|0.004206|
|A33|88|28|60|0.085714|0.093333|-0.085158|0.000649|
|A34|293|50|243|0.347143|0.166667|0.733741|0.132423|