[머신러닝/딥러닝] 안전 운전자 예측 (1)
<머신러닝. 딥러닝 문제해결 전략> 2부 8장 실습하고 해당 내용을 정리한 내용입니다.
1. 경진대회 이해
https://www.kaggle.com/competitions/porto-seguro-safe-driver-prediction
Porto Seguro’s Safe Driver Prediction | Kaggle
www.kaggle.com
2부 8장에서 사용되는 경진대회는 안전 운전자 예측 경진대회 입니다.
2017년 9월 30일에서 2017년 11월 30일까지 두 달 동안 개최되었던 대회이며, 총 5,156팀이 참가했습니다.
안전 운전자 예측 경진대회는 포르투 세구로라는 브라질 보험 회사에서 주최한 대회입니다. 포르투 세구로는 지난 20년 간 머신러닝을 활용해왔지만, 자동차 보험과 관련해서 보다 정확한 예측 모델을 만들고자 본 대회를 열었습니다. 사고를 낼 가능성이 낮은 안전 운전자에게는 보험료를 적게 청구하고, 사고 가능성이 높은 난폭 운전자 에게는 많은 보험료를 청구해야 합니다. 보험금 청구 예측 모델이 부정확하다면 안전 운전자들에게 불만을 초래하게 됩니다. 고객 만족도도 높이고 회사 수익도 높이려면 모델이 정확해야 합니다. 따라 운전자가 보험금을 청구할 확률을 정확히 예측하는 모델을 만드는 게 본 경진대회 목표입니다.
주어진 데이터는 포르투 세구로가 보유한 고객 데이터입니다. 물론 데이터로부터 고객을 특정할 수 없도록 비식별화되어 있습니다. 보기에는 결측값이 없는 것으로 나타나지만 사실 주어진 데이터에 결측값이 꽤 많습니다. 결측값은 -1로 기록돼 있습니다. 결측값을 어떻게 해석할지도 알아보겠습니다.
마지막으로 타깃값은 0또는 1입니다. 값이 0이면 운전자가 보험금을 청구하지 않는다는 뜻이고, 1이면 청구한다는 뜻입니다. 타깃값이 두 개이므로 본 경진대회는 이진분류 문제에 속합니다.
2. 탐색적 데이터 분석
이번에 진행될 경진대회의 탐색적 데이터 분석의 순서는 아래와 같습니다.
캐글 노트북 환경 설정 | |
데이터 둘러보기 | 피처 요약표 |
데이터 시각화 | 각종 피처의 분포 확인 (타깃값, 이진 피처, 명목형 피처, 순서형 피처, 연속형 피처) |
분석 정리 및 모델링 전략 |
01. 데이터 둘러보기
가장 먼저 데이터를 불러오겠습니다. 이때 index_col에 'id'를 전달해 id 열을 인덱스로 지정하겠습니다.
훈련 데이터와 테스트 데이터 크기를 확인해 보겠습니다.
훈련 데이터는 약 59만 개, 테스트 데이터는 약 89만 개입니다.
훈련 데이터보다 테스트 데이터가 더 많다는 것과 타깃값을 제외하면 피처가 총 57개란 점을 알 수 있습니다.
분석 결과 |
지금까지의 경진대회에 비해 데이터가 크고 피처 수도 많습니다 |
훈련 데이터의 첫 다섯 행을 출력해보겠습니다.
피처가 많아 중간에 생략되어 있습니다. 테스트 데이터의 첫 다섯 행도 출력해보겠습니다.
테스트 데이터 역시 훈련 데이터와 마찬가지로 생략되어 출력되어 있습니다. 제출 샘플 데이터도 살펴보겠습니다.
타깃값 확률이 0.0364로 일괄 일력돼 있습니다. 앞의 예측과 같이 예측해야 하는 값은 '타깃값이 1일 확률'입니다.
이때 타깃값 0은 운전자가 보험금을 청구하지 않는 경우, 타깃값 1은 청구하는 경우를 의미합니다.
즉, 운전자가 보험금을 청구할 확률이 얼마나 되는지를 예측하는 것을 의미합니다.
다음으로 info()를 호출해 훈련 데이터를 상세히 살펴보겠습니다.
훈련 데이터 59만 개에 관한 정보가 출력되었습니다. 데이터 타입은 int64와 float64 중 하나입니다.
피처명을 한번 보겠습니다. 비식별화되어 있어서 각 피처가 어떤 의미 인지 알 수 없습니다. 다만 아래와 같이 일정한 형식이 있습니다.
ps_[분류]_[분류별 일련번호]_[데이터 종류]
ps_ind_01 (생략가능) <- 순서형 또는 연속형 피처
ps_reg_02_bin <- 이진 피처
ps_car_03_cat <- 명목형 피처
ps_calc ....
맨 처음은 모두 ps로 시작합니다. 그 다음은 분류가 나옵니다. 분류로는 ind, red, car, calc가 있습니다. 분류 다음엔 해당 분류에서의 일련번호가 나옵니다. 마지막은 데이터 종류입니다. 데이터 종류가 bin이면 이진 피처, cat이면 명목형 피처라는 뜻입니다. 데이터 종류가 생략돼 있으면 순서형 또는 연속형 피처입니다.
여기서 분류와 일련번호로는 어떠한 정보도 얻지 못합니다. 비식별화되어 있어서 각 분류가 무슨 의미인지 알지 못하기 때문입니다. 마지막의 데이터 종류에서만 유의미한 정보를 얻을 수 있습니다.
앞의 출력 결과를 보면 모든 피처에 결측값이 없다고 나오지만, 실제로는 그렇지 않습니다. 왜냐하면 값이 누락된 곳에 -1이 입력되어 있어서 결측값이 없다고 판단되었기 때문입니다. 이런 경우에는 -1을 np.NaN으로 변환한 다음 개수를 세어줘야 합니다.
피처가 많다보니 결측값을 시각화해서 한눈에 보는게 좋겠습니다. 이럴때 missingno 패키지를 사용합니다. missingno는 결측값을 시각화하는 패키지입니다. missingno가 제공하는 bar()함수를 활용해서 훈련 데이터에 결측값이 얼마나 있는지 살펴보겠습니다. bar()함수는 결측값을 막대 그래프 형태로 시각해줍니다.
ⓐ 먼저 -1을 np.NaN으로 바꿨습니다. 그런데 훈련 데이터 값을 직접 바꾸면 안 되기 떄문에 중간에 copy() 함수로 복사본을 만드어 진행했습니다. 원본의 결측값은 -1로 그대로 유지해야 나중에 다른 시각화를 할 수 있습니다.
피처가 57개나 되니 ⓑ피처를 반으로 나눠 처음 28개를 시각화하면 다음 그림이 출력됩니다.
막대 그래프 높이가 낮을수록 결측값이 많다는 의미입니다. 그래프 아래 피처명이 기재돼 있고 그래프 위에는 정상 값이 몇개인지가 표시되어 있습니다. ps_reg_03, ps_car_03_cat, ps_car_05_cat 피처에 특히 결측값이 많습니다.
나머지 피처들의 결측값도 살펴보겠습니다.
ps_car_14에 결측값이 좀 있고 나머지 피처에는 거의 없습니다. 이 결측값들을 어떻게 처리해야 할지는 이후 알아보겠습니다.
결측값 매트릭스 형태로 시각화하기 결측값을 매트릭스 형태로 시각화할 수도 있습니다. bar() 대신 matrix() 함수를 사용하면 됩니다. ![]() 오른쪽 막대는 결측값의 상대적인 분포를 보여줍니다. 검은색으로 뾰족하게 튀어나는 부분이 결측값이 몰려있는 행을 의미합니다. 왼쪽에 표시는 22는 결측값이 없는 열 개수를, 오른쪽 28은 전체 열 개수를 뜻합니다. |
- 피처 요약표
위에서 살펴 본 것처럼 피처의 종류가 다양할 때는 한눈에 파악할 수 있게 피처 요약표를 만드는 게 좋습니다. 피처 요약표가 있으면 데이터 관리도 편하고, 추후 그래프를 그릴 때도 활용할 수 있습니다.
이전의 내용에서 만든 피처 요약표는 데이터 타입, 결측값 개수, 고윳값 개수, 1~3행에 입력된 값을 보여줬습니다. 하지만 이번 경진대회에서 제공한 데이터는 숫자로 구성되어 있어 1~3행에 입력된 값은 따로 추가하지 않겠습니다. 아울러, 시각화 시 피처를 추출하는 데 필요한 데이터 종류를 추가해주도록 하겠습니다.
두 곳만 살펴보겠습니다. 결측값이 -1이므로 결측값 개수를 구할려면 -1의 개수를 구해야 합니다.
ⓐ 처럼 (df == -1).sum().values 코드로 피처별 -1 개수를 구할 수 있습니다.
ⓑ에서는 for문을 순회하며 데이터 종류를 추가했습니다. 피처명에 'bin'이 포함되어 있거나 타깃 열이면 이진형 데이터이고, 'cat'이 포함되어 있으면 명목형입니다.또한 데이터 타입이 float이면 연속형 데이터 이며, int면 순서형 데이터 입니다.
생성한 피처 요약표를 출력해보겠습니다. 결과는 아래와 같습니다.
summary = resumetable(train)
summary
데이터 세트 형상: (595212, 58)
인덱스는 피처명입니다. 데이터 타입 열에는 해당 피처의 데이터 타입이 기재되어 있습니다. 결측값 개수와 고윳값 개수도 한눈에 볼 수 있습니다. 데이터 종류 열에는 이진형, 명목형, 연속형, 순서형 피처가 구분되어 있습니다. 이렇게 피처 요약표를 만들면 대략적으로 파악하기 쉽고 데이터를 관리하고 편합니다.
피처 요약표만으로 모델링에 도움이 될 만한 정보를 얻기는 어렵지만, 본격적으로 분석하기에 앞서 어떤 데이터가 있는지 한눈에 파악하는데 도움을 줍니다. 또한, 다음과 같이 피처 요약표에서 원하는 피처를 추출할 수 있습니다.
예시로 명목형 피처만 추출해보겠습니다.
데이터 타입이 실수형인 피처도 구해보겠습니다.
이렇게 피처 요약표가 있으면 원하는 피처를 추출하기 편리합니다. 데이터 시각화에서 피처 요약표에서 추출한 피처를 활용하겠습니다.
02. 데이터 시각화
데이터 시각화를 통해 모델링에 필요한 피처는 무엇이고 ,필요없는 피처는 무엇인지 선별해보겠습니다.
먼저 타깃값 분포를 활용해 타깃값이 얼마나 불균형한지 알아보겠습니다. 또한 이진 피처, 명목형 피처, 순서형 피처, 연속형 피처의 고윳값별 타깃값 비율을 알아보겠습니다. 막대그래프로 그릴 것이며, 이러한 과정을 통해 타깃값 비율로 모델링 시 어떤 피처를 제거해야 할지 알 수 있습니다.
우선 시각화 라이브러리를 불러오겠습니다.
import seaborn as sns
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
- 타깃값 분포
타깃값 분포를 보여주는 코드는 다음과 같으며 막대 그래프 상단에 비율까지 표시했습니다.
def write_percent(ax, total_size):
'''도형 객체를 순회하며 막대 그래프 상단에 타깃값 비율 표시'''
for patch in ax.patches:
height = patch.get_height() # 도형 높이(데이터 개수)
width = patch.get_width() # 도형 너비
left_coord = patch.get_x() # 도형 왼쪽 테두리의 x축 위치
percent = height/total_size*100 # 타깃값 비율
# (x, y) 좌표에 텍스트 입력
ax.text(left_coord + width/2.0, # x축 위치
height + total_size*0.001, # y축 위치
'{:1.1f}%'.format(percent), # 입력 텍스트
ha='center') # 가운데 정렬
mpl.rc('font', size=15)
plt.figure(figsize=(7, 6))
ax = sns.countplot(x='target', data=train)
write_percent(ax, len(train)) # 비율 표시
ax.set_title('Target Distribution');
결과를 살펴보면 타깃값 0은 96.4%를 차지하며 1은 단 3.6%만을 차지합니다. 전체 운전자 중 3.6%만 보험금을 청구했다는 뜻입니다. 이는 차 사고가 그리 흔하게 나지 않아 소수의 운전자만 보험금을 청구했다는 의미입니다. 타깃값이 불균형합니다.
타깃값이 불균형 하기에 비율이 작은 타깃값 1을 잘 예측하는게 중요합니다. 따라 각 피처의 분포를 알아보기 보다는, 각 피처의 고윳값별 타깃값이 1인 비율을 알아보겠습니다. 고윳값별 타깃값 1 비율을 통해 해당 피처가 모델링에 필요한 피처 인지 알 수 있습니다.
예를 들어 피처 A에 고윳값 a, b가 있다고 하면, 이때 고윳값 a,b별로 타깃값 1 비율이 어떻게 되는지를 확인하는 것입니다.고윳값 별로 타깃값 1 비율이 똑같거나 통계적 유효성이 떨어진다면 이는 무언가를 분별하기 어렵다는 의미가 되므로 예측에 큰 도움이 되지 않습니다. 즉, 고윳값에 따라 타깃값 비율이 달라야 그 피처가 타깃값 예측에 도움이 됩니다.
또한 타깃값 1 비율의 통계적 유효성이 떨어져도 불필요한 피처가 됩니다. 통계적 유효성은 barplot()을 통해 나타나는 신뢰구간으로 판단합니다. 이때 신뢰구간이 넓다면 이는 신뢰하기 어렵다는 의미가 됩니다. 즉, 신뢰구간이 좁아서 어느 정도 통계적으로 유효성이 되어야 타깃값 예측에 도움이 된다는 의미입니다.
위의 내용을 정리하면, 고윳값별 타깃값 1 비율이 충분히 차이가 나고 신뢰구간도 작은 피처여야 모델링에 도움이 된다는 의미입니다. 따라 이러한 피처가 아닌 피처들을 모두 제거하는 것이 좋습니다.
- 이진 피처
이진 피처의 고윳값별 타깃값 비율을 구해보겠습니다. 이전에 사용했던 함수를 응용하여 막대그래프로 그려보겠습니다. 다음의 plot_target_ratio_by_features() 함수는 앞의 plot_car_dist_with_true_ratio()함수와 유사합니다. 이전에는 교차분석표를 활용해 카운트플롯과 포인트 플롯을 그렸지만, 이번 plot_target_ratio_by_features()함수는 막대 그래프를 그린다는 점이 다릅니다.
import matplotlib.gridspec as gridspec
def plot_target_ratio_by_features(df, features, num_rows, num_cols,
size=(12, 18)):
mpl.rc('font', size=9)
plt.figure(figsize=size) # 전체 Figure 크기 설정
grid = gridspec.GridSpec(num_rows, num_cols) # 서브플롯 배치
plt.subplots_adjust(wspace=0.3, hspace=0.3) # 서브플롯 좌우/상하 여백 설정
for idx, feature in enumerate(features):
ax = plt.subplot(grid[idx])
# ax축에 고윳값별 타깃값 1 비율을 막대 그래프로 그리기
sns.barplot(x=feature, y='target', data=df, palette='Set2', ax=ax)
이 함수를 이용해 그래프를 그려보겠습니다. 주어진 데이터 중 이진 피처를 총 18개 입니다. 그려야할 그래프가 많기에 서브플롯을 3열 행으로 배치하겠습니다.
bin_features = summary[summary['데이터 종류'] == '이진형'].index # 이진 피처
# 이진 피처 고윳값별 타깃값 1 비율을 막대 그래프로 그리기
plot_target_ratio_by_features(train, bin_features, 6, 3) # 6행 3열 배치
이진 피처이기 때문에 고윳값이 0과 1, 두 개뿐입니다.
1번 target 그래프는 타깃값 그래프 이므로 무시하고 2번부터 확인하겠습니다.
2번의 ps_ind_06_bin 피처 그래프를 먼저 살펴보겠습니다. 이 피처는 값이 0일 때, 타깃값이 1인 비율이 4%(0.04) 정도 입니다. 나머지 96%의 타깃값은 0입니다. 값이 1일 때에는 타깃값 1이 2.8% 정도 차지 합니다.
이를 표로 정리하면 다음과 같습니다.
고윳값 | 타깃값 1 비율 | 타깃값 0 비율 |
0 | 4% | 96% |
1 | 2.8% | 97.2% |
종합하면 ps_ind_06_bin 피처는 고윳값별로 타깃값 비율이 다릅니다. 따라서 타깃값을 추정하는 데 예측력이 있습니다. 또한 신뢰구간이 좁기에 모델링에 도움이 되는 피처 입니다.
위와 같은 방법으로 각각을 분석하면 모델링시 제거할 피처는 다음 표와 같습니다.
서브플롯 위치 | 피처명 | 제거해야 하는 이유 |
6번~9번 (2행 3열 ~ 3행 3열) |
ps_ind_10_bin ~ ps_ind_13_bin | 신뢰구간이 넓어 통계적 유효성이 떨어짐 |
13번~18번 (5행 0열 ~ 6행 2열) |
ps_calc_15_bin ~ ps_calc_20_bin | 고윳값별 타깃값 비율 차이가 없어 타깃값 예측력이 없음 |
여기서 주목해야 할 점이 하나 존재하는데, calc 분류의 이진피처는 모두 타깃값 비율에는 차이가 없다는 사실입니다. calc 분류의 다른 피처도 차이가 없는지 추후 알아보겠습니다.
- 명목형 피처
이번에는 명목형 피처 14개로 동일한 그래프를 그려보겠습니다. 명목형 피처는 고윳값 개수가 이진 피처보다 많습니다. 고윳값이 많으면 그래프가 가로로 길어지니 이번에는 서브플롯을 7행 2열로 그리겠습니다.
nom_features = summary[summary['데이터 종류'] == '명목형'].index # 명목형 피처
plot_target_ratio_by_features(train, nom_features, 7, 2) # 7행 2열
이번에는 -1을 포함한 피처도 많습니다. -1은 결측값 입니다. 보통 결측값은 적절히 처리합니다. 만약 결측값이 많지 않다면 다른 값으로 대체하고, 결측값이 많다면 해당 피처 자체를 제거합니다. 하지만 결측값 자체가 타깃값 예측에 도움을 주는 경우도 있습니다.
분석 결과 |
결측값 자체에 타깃값 예측력이 있다면 고윳값으로 간주 (결측값 처리 필요 없음) |
1번 그래프의 ps_ind_02_cat 피처를 보겠습니다. 결측값 -1이 다른 고윳값들보다 타깃값 1 비율이 큽니다. 신뢰구간이 넓다는 점을 감안하더라도 비율이 확실히 큽니다. 이러한 상황에서 결측값을 다른 값으로 대체하게 되면 모델 성능이 더 나빠질 수 있습니다. 왜냐하면 결측값 자체가 타깃값에 대한 예측력이 있기 때문입니다. 따라서 결측값을 그대로 두고 모델링 하겠습니다. 이는 -1인 결측값 역시 하나의 고윳값으로 간주하는 것과 같습니다.
5번 그래프 ps_car_02_cat 피처 역시 살펴보겠습니다. -1일 때, 타깃값 1의 비율은 0%입니다. 이는 ps_car_02_cat 피처값이 -1이면 타깃값이 0이라는 의미입니다. 이 역시 결측값이 타깃값을 예측하는데 도움을 줍니다.
1번 그래프 (ps_ind_02_cat)와 마찬가지로 2번(ps_ind_04_cat), 4번(ps_car_01_cat) 그래프 역시 모델링에 필요한 피처인 것을 알 수 있습니다.
마지막으로 13번 그래프(ps_car_10_cat)의 피처를 보겠습니다. 세 고윳값은 타깃값 1의 평균 비율이 비슷합니다. 그리고 고윳값 2의 신뢰구간이 유독 넓습니다. 이 피처 역시 제거하기에는 애매합니다. 제거한 경우와 제거하지 않은 경우에서 car_10_cat 피처를 제거하지 않은 경우에 성능이 더 좋았기에 이 역시도 제거하지 않겠습니다.
분석 결과 |
명목형 피처는 모두 모델링에 이용 |
- 순서형 분포
순서형 피처를 살펴보겠습니다.
ord_features = summary[summary['데이터 종류'] == '순서형'].index # 순서형 피처
plot_target_ratio_by_features(train, ord_features, 8, 2, (12, 20)) # 8행 2열
먼저 3번(ps_ind_14) 그래프를 보겠습니다. 고윳값 0, 1, 2, 3의 타깃값 비율을 큰 차이가 없고, 고윳값 4번의 신뢰 구간은 넓습니다. 신뢰구간이 상당히 넓어 통계적 유효성이 떨어집니다. 따라 pd_ind_14 피처는 제거하겠습니다.
다음 6번(pd_calc_04)그래프 부터 16번(ps_calc_14)그래프(3행 2열부터 8행 2열)를 살펴보겠습니다. 타깃값 비율이 다른 고윳값도 있긴 하지만, 그 고유값은 신뢰구간이 넓어 통계적 유효성이 떨어지며 나머지는 고윳값별 타깃값 비율이 거의 비슷합니다. 따라 이 피처들은 모두 제거하겠습니다. 앞서 '이진 피처'에서 calc 분류에 해당하는 이진 피처를 제거한 것과 같이 순서형 피처에서도 calc 분류의 모든 피처는 제거하게 되었습니다.
제거해야할 순서형 피처를 정리하면 다음과 같습니다.
서브플롯 위치 | 피처명 | 제거해야 하는 이유 |
3번 그래프 | ps_ind_14 | 타깃값 비율의 신뢰구간이 넓어 통계적 유효성이 떨어짐 |
6번~16번 그래프 | ps_calc_04 ~ ps_calc_!4 | 고유값별 타깃값 비율 차이가 없음. 타깃값 비율이 다르더라도 신뢰구간이 넓어 통계적 유효성이 떨어짐 |
- 연속형 분포
마지막으로 연속형 피처 차례입니다. 연속형 피처는 연속된 값이므로 고윳값이 굉장히 많습니다. 따라 고윳값별 1 비율을 구하기가 힘듭니다. 그렇기에 값을 몇 개의 구간으로 나눠서 구간별 타깃값 비율을 알아보겠습니다.
연속형 데이터를 구간으로 나눌때 사용하는 함수는 pandas의 cut()함수 입니다. 다음은 cut()함수를 활용해 여러 개의 값을 3개 구간으로 나누는 예입니다. 함수의 첫 번째 인수가 값들의 리스트 이며, 두번째 인수가 나눌 구간의 개수입니다.
입력된 결과를 비교하면 다음 그림과 같습니다. 왼쪽이 원본이며, 오른쪽이 적용후 결과입니다.
연속형 피처 원본 (float 타입) |
pd.cut() 적용 후 (category 타입) |
1.0 | (0.997, 2.0] |
1.5 | (0.997, 2.0] |
2.1 | (2.0, 3.0] |
2.7 | (2.0, 3.0] |
3.5 | (3.0, 4.0] |
4.0 | (3.0, 4.0] |
'('는 초과, ']'는 이하를 의미합니다. 즉, (0.997, 2.0]은 0.997 초과 2 이하인 구간을 의미합니다. |
이 방법을 활용해 연속형 피처의 구간별 타깃값 1 비율을 구해보겠습니다. 그래프를 그리는 코드는 앞서 정의한 plot_ratio_by_features와 유사하며, cut() 함수로 구간을 나누는 부분만 다릅니다.
cont_features = summary[summary['데이터 종류'] == '연속형'].index # 연속형 피처
plt.figure(figsize=(12, 16)) # Figure 크기 설정
grid = gridspec.GridSpec(5, 2) # GridSpec 객체 생성
plt.subplots_adjust(wspace=0.2, hspace=0.4) # 서브플롯 간 여백 설정
for idx, cont_feature in enumerate(cont_features):
# 값을 5개 구간으로 나누기
train[cont_feature] = pd.cut(train[cont_feature], 5)
ax = plt.subplot(grid[idx]) # 분포도를 그릴 서브플롯 설정
sns.barplot(x=cont_feature, y='target', data=train, palette='Set2', ax=ax)
ax.tick_params(axis='x', labelrotation=10) # x축 라벨 회전
출력된 결과를 살펴보겠습니다. 모델링 시, 8번(ps_calc_01), 9번(ps_calc_02),10번(ps_calc_03)는 고윳값별로 타깃값 비율이 서로 비슷하기에 이를 제거하겠습니다. 그 외 나머지 피처는 모두 타깃값 비율이 다르기에 타깃값 예측령이 있는 피처로 사용하도록 하겠습니다.
이를 표로 정리하면 다음과 같습니다.
서브플롯 위치 | 피처명 | 제거해야 하는 이유 |
8번~10번 그래프 | ps_calc_01~ps_calc_03 | 구간별 타깃값 비율 차이가 없음 |
이로써 calc 분류의 피처는 데이터 종류에 상관없이 모두 제거해야한다는 사실을 알게 되었습니다. 이 피처들은 고윳값 혹은 구간별로 타깃값 비율이 거의 같습니다. 즉 타깃값을 구분하는 예측 능력이 떨어진다는 의미입니다.
- 연속형 분포Ⅱ
다음으로 연속형 피처 간 '상관관계'를 파악해보겠습니다. 일반적으로 강한 상관관계를 보이는 두 피처가 있으면 둘 중 하나를 제거하는 게 좋습니다. 상관관계가 강하면 타깃값 예측력도 비슷하다는 의미이며, 그런 피처가 있으면 모델 성능이 떨어질 수도 있습니다.
피처 간 상관관계를 파악하기 위해 히트맵을 그려보겠습니다. 그런데 현재 피처에 결측값이 존재합니다. 결측값이 있으면 상관관계를 올바르게 구하지 못하므로 먼저 결측값을 제거하겠습니다. 그러기 위해 -1을 np.NaN으로 변환한 train_copy 에서 np.NaN을 제거하겠습니다
train_copy = train_copy.dropna() # np.NaN 값 삭제
이때 dropna()는 np.NaN를 제거해주는 함수입니다.
이제 결측값을 제거한 train_copy를 활용해 상관관계 히트맵을 그려보겠습니다. 히트맵은 시본의 heatmap()함수로 그릴 수 있습니다.
plt.figure(figsize=(10, 8))
cont_corr = train_copy[cont_features].corr() # 연속형 피처 간 상관관계
sns.heatmap(cont_corr, annot=True, cmap='OrRd'); # 히트맵
가장 강한 상관관계를 보이는 피처는 ps_car_12와 ps_car_14입니다. 두 피처 간 상관계수는 0.77입니다. 둘 중 하나를 제거해야할 만큼 강한 상관관계를 보이는 것은 아니지만 제거하는 것이 더욱 성능이 좋아졌기에 제거하도록 하겠습니다.
분석 결과 |
상관관계가 강한 피처 제거(ps_car_14) |
다음 ps_reg_02와 ps_reg_03 피처 간 상관계수는 0.76입니다. 이는 제거하는 것이 성능이 떨어졌습니다. 따라 이는 남겨놓도록 하겠습니다.
이번 데이터의 분석을 정리하면 이는 다음과 같습니다.
1. 이전의 경진대회에 비해 데이터가 크고 피처 수도 많습니다.
2. 피처명만으로 분류별 혹은 데이터 종류별 피처들을 구분해 추출해낼 수 있습니다.
3. 결측값 처리 : 결측값 자체 타깃값 예측력이 있다면 고윳값으로 간주합니다.
4. 결측값 처리 : 피처 간 상관관계 분석은 결측값 제거 후 수행합니다.
5. 피처 제거 : 신뢰구간이 넓으면 통계적 유효성이 떨어져 믿을 수 없습니다. (ps_ind_14, ps_calc_04~ps_calc_14)
6. 피처 제거 : 고윳값별 타깃값 비율에 차이가 없다면 타깃값 예측력이 없습니다. (ps_calc_04~ps_calcs_14)
7. 피처 제거 : (연속형 데이터의 경우) 구간별 타깃값 차이가 거의 없다면 타깃값 예측력이 없습니다. (ps_calc_01~ps_calc_03)
8. 피처 제거 : 일반적으로 강한 상관관계를 보이는 두 피처가 있으면 둘 중 하나를 제거하는게 좋습니다. (ps_car_14)