본문 바로가기

연습장

[Kaggle] 캐글 상위권 코드 보고 공부하는 타이타닉 예제 심화 Feature Engineering (나이대, 요금대, 가족으로 변수 묶기/문자형 자료 변환/칼럼 삭제)

www.kaggle.com/ash316/eda-to-prediction-dietanic

 

EDA To Prediction(DieTanic)

Explore and run machine learning code with Kaggle Notebooks | Using data from Titanic: Machine Learning from Disaster

www.kaggle.com

(※ 오늘은 이 캐글러의 공유 코드를 활용해 공부하는 내용입니다.)

 

1장. EDA

1) feature 분석

2) 여러 feature들간의 관계, 경향 찾기

 

2장. Feature Engineering and Data Cleaning

1) 새로운 Feature 추가

2) 반복되는 feature 제거

3) 모델링에 적합한 형태로 feature 변환

 

3장. Predictive Modeling

1) 기본적인 알고리즘 실행

2) CrossValidation(교차 검증)

3) Ensembling(앙상블 기법)

4) 중요한 특성 추출(Important Feature Extraction)

 

오늘은 Feature Engineering이다!


2장. Feature Engineering & Data Cleaning

 

## Feature Engineering

 

1) 나이 특성 집단별로 묶어주기

 

나이 특성은 연속형 변수이지만 머신러닝을 위해서 특정 나이로 입력하기보다 나이대로 묶어주는 것이 머신러닝에 더욱 효과적이다.

 

캐글러는 최고령 승객이 80살이므로 나이 범주를 5개로 나누어 0-16, 17-32, ... 65-80으로 나누어주었다.

 

이것이 합리적인 방법인지 궁금했다.

 

위는 저번 포스팅에서 살펴본, 결측치를 처리한 후의 나이대에 따른 사망, 생존 빈도수 그래프이다.

 

먼저 0세에서 15세의 생존, 사망 빈도수는 다른 나이대와 비교해서 분명해보인다. 0-16세는 괜찮은 범주다.

65-80세의 범주도 나쁘지 않아 보인다.

 

그 사이의 나이대가 조금 애매하긴하다.

 

하지만 비교적 괜찮다고 판단해서 캐글러가 나눈 나이대 범주를 그대로 따르기로 했다.

 

data['Age_band'] = 0
data.loc[data['Age'] <= 16, 'Age_band'] = 0
data.loc[(data['Age'] > 16) & (data['Age'] <= 32), 'Age_band'] = 1
data.loc[(data['Age'] > 32) & (data['Age'] <= 48), 'Age_band'] = 2
data.loc[(data['Age'] > 48) & (data['Age'] <= 64), 'Age_band'] = 3
data.loc[data['Age'] > 64, 'Age_band'] = 4

'Age_band' 칼럼을 새로 추가하고 .loc() 함수를 사용해 지정한 나이대에 따라 0부터 4의 값을 부여했다.

 

data['Age_band'] = 0
data.loc[data['Age'] <= 16, 'Age_band'] = 0
data.loc[(data['Age'] > 16) & (data['Age'] <= 32), 'Age_band'] = 1
data.loc[(data['Age'] > 32) & (data['Age'] <= 48), 'Age_band'] = 2
data.loc[(data['Age'] > 48) & (data['Age'] <= 64), 'Age_band'] = 3
data.loc[data['Age'] > 64, 'Age_band'] = 4

Pclass와 Name 특성을 참고해 나이대를 부여해서 그런지 확실히 Age_band의 빈도수와 캐글러의 빈도수 사이에 큰 차이가 발생했다.

 

sns.factorplot('Age_band', 'Survived', data = data, col = 'Pclass')
plt.show()

나이대별 생존률의 factorplot을 Pclass로 나누어 그렸다.

(sns.factorplot('Age_band', 'Survived', data = data, col = 'Pclass')

 

캐글러가 그린 factor plot은 3등석에서 16-32세 나이대에서 나쁘지 않은 생존률을 보였는데, 내 플롯을 보면 차이가 크게 느껴질 정도로 생존률이 낮아졌다.

 

나이 결측치를 다르게 처리한 결과가 스노우볼처럼 굴러 점점 커지고 있는데, 그 끝은 어떨지 계속 지켜봐야겠다.


2) 가족 혹은 혼자로 특성 묶어주기

 

혼자 탑승한 사람은 'Alone'으로, 가족 구성원이 있는 사람은 'Family_size' 칼럼을 만들어서 SibSp와 Parch를 합하자.

 

sns.factorplot('Family_Size', 'Survived', data = data, ax = ax[0])
ax[0].set_title('Family_Size vs Survived')

sns.factorplot('Alone', 'Survived', data = data, ax = ax[1])
ax[1].set_title('Alone vs Survived')

plt.show()

subplot에 자꾸 문제가 생겨서 그냥 따로 하나하나씩 그려보았다.

자족 구성원 크기별 생존률
혼자냐 아니냐에 따른 생존률

Family_size가 1-3일 때 생존률이 50% 이상이고, 혼자일 때 생존률은 30%로 매우 낮았다.

 

Family_size가 4이상일 때 생존률도 굉장히 낮아서 중요한 피쳐로 사용할 수 있다고 생각했다.

 

sns.factorplot('Alone', 'Survived', hue = 'Sex', data = data, col = 'Pclass')
plt.show()

sns.factorplot('Alone', 'Survived', hue = 'Sex', data = data, col = 'Pclass')

-> 혼자 여부와 생존률에 대한 factorplot을 그리는데 성별로 그룹화하고, Pclass별로 그래프를 그려라.

1, 2등석 승객인 여성은 혼자든 아니든 생존률이 둘 다 높았다.

 

3등석 여성은 혼자가 아니어야 생존률이 더 높았다.

 

2등석 남성 승객이 혼자가 아닐 때 생존률이 제일 낮았다. (가족을 위해 희생했다고 받아들여야 하나..?)

 

3등석 남자는 혼자든 아니든 생존률이 극히 낮았다.


3) 요금 범위 특성 나누기

 

요금 역시 연속형 변수이기 때문에 요금대로 범주를 나눠주는 것이 좋다.

 

이를 위해 pandas의 qcut 함수를 사용한다.

 

data['Fare_Range'] = pd.qcut(data['Fare'], 4)
data.groupby(['Fare_Range'])['Survived'].mean().to_frame().style.background_gradient(cmap = 'summer_r')

data['Fare_Range'] = pd.qcut(data['Fare'], 4)

-> Fare_Range라는 새로운 칼럼을 만드는데 (data['Fare_Range'] = )

pandas의 qcut이라는 함수를 써서 Fare 특성을 4구간으로 나눈다. ( pd.qcut(data['Fare'], 4) )

 

data.groupby(['Fare_Range'])['Survived'].mean().to_frame().style.background_gradient(cmap = 'summer_r')

-> Fare_Range 범주별로 묶어서 Survived 특성의 평균을 읽어라. ( data.groupby(['Fare_Range'])['Survived'].mean() )

그것을 데이터프레임화해라. ( .to_frame() )

먼저, qcut함수는 알아서 요금의 범위를 (-0.001, 7.91], (7.91, 14,454], (14.454, 31.0], (31.0, 512.329] 네 구간으로 나눴다.

 

요금_구간에 따른 생존률은 요금이 높을수록 더 높아보였다.

 

data['Fare_cat'] = 0
data.loc[data['Fare'] <= 7.91, 'Fare_cat'] = 0
data.loc[(data['Fare'] > 7.91) & (data['Fare'] <= 14.454), 'Fare_cat'] = 1
data.loc[(data['Fare'] > 14.454) & (data['Fare'] <= 31), 'Fare_cat'] = 2
data.loc[(data['Fare'] > 31) & (data['Fare'] <= 513.329), 'Fare_cat'] = 3

요금구간 범주를 Fare_cat이라는 칼럼에 지정해주었다.

 

sns.factorplot('Fare_cat', 'Survived', hue = 'Sex', data = data)
plt.show()

Fare_cat이 0이면 낮은 요금 3이면 높은 요금이다.

 

남성의 경우, 요금구간이 높아질수록 생존률이 높아졌다. 여성은 가장 높은 요금구간에서 생존률이 매우 높았다.


4) 문자로 된 범주 숫자형으로 변환

 

모델 훈련을 위해서는 문자 범주를 그대로 쓸 수 없기 때문에 문자형 범주를 숫자형으로 변환한다.

 

data['Sex'].replace(['male', 'female'], [0, 1], inplace = True)
data['Embarked'].replace(['S', 'C', 'Q'], [0, 1, 2], inplace = True)
data['Initial'].replace(['Mr', 'Mrs', 'Miss', 'Master', 'Other'], [0, 1, 2, 3, 4], inplace = True)

5) 필요없는 특성 삭제

 

이제 더 필요없는 특성을 삭제한다.

data.drop(['Name', 'Age', 'Ticket', 'Fare', 'Cabin', 'Fare_Range', 'PassengerId'],
          axis = 1, inplace = True)

칼럼을 drop했다.

 

다음은 히트맵을 만들어서 만든 변수들 사이 상관계수를 확인해 더 지워야할 것을 확인한다.

sns.heatmap(data.corr(), annot = True, cmap = 'RdYlGn', linewidths = 0.2, annot_kws = {'size': 20})
fig = plt.gcf()
fig.set_size_inches(18, 15)
plt.xticks(fontsize = 14)
plt.yticks(fontsize = 14)
plt.show()

Fmaily_Size랑, SibSp, Parch, Alone에서 높은 상관관계가 있을 수 밖에 없었다.

근데 이 캐글러는 특별히 삭제하지 않았나보다.

 

이유는 모르겠다.

 

삭제를 안 하는 것이 더 유리한 것인가..!


캐글러를 따라서 Feature Engineering과 데이터 처리를 끝냈다.

 

다음은 모델링이다..!