이번 글에서는 사이킷런을 이용하여 타이타닉 생존자 예측을 해보자.
데이터는 kaggle을 참고하였다.
kaggle에서 타이타닉 train 데이터를 로드하고, 데이터를 분석해보자.
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
pd.set_option('display.max_rows', 100)
pd.set_option('display.max_colwidth', 100)
pd.set_option('display.max_columns',100)
titanic_df = pd.read_csv('titanic_train.csv')
titanic_df
우리가 예측해야할 Target은 survived 생존 여부이며, 각 feature 들은 위와 같다.
각 feature들의 정보를 살펴보자.
print(titanic_df.info()) # 데이터 프레임의 모든 기본 정보를 확인
titanic_df.describe() # 기초 통계 정보 확인
위에서 살펴본 feature들의 데이터 전처리를 해보자.
널 값 처리 및 라벨 인코딩과 불필요한 피처를 제거하고, 이를 보기 좋게 함수화 해보자.
# Null 값 처리
def fillna(df):
df['Age'].fillna(df['Age'].mean(), inplace=True)
df['Cabin'].fillna('N', inplace=True)
df['Embarked'].fillna('N', inplace=True)
print('데이터 세트 Null 값 개수: ', df.isnull().sum().sum())
return df
# 머신러닝 알고리즘에 불필요한 피처 제거
def drop_features(df):
df.drop(['PassengerId', 'Name', 'Ticket'], axis=1, inplace=True)
return df
# 레이블 인코딩 수행
def format_features(df):
df['Cabin'] = df['Cabin'].str[:1]
features = ['Cabin', 'Sex', 'Embarked']
for feature in features:
le = LabelEncoder()
le = le.fit(df[feature])
df[feature] = le.transform(df[feature])
return df
# 앞에서 설정한 Data Preprocessing 함수 호출
def transform_feature(df):
df = fillna(df)
df = drop_features(df)
df = format_features(df)
return df
Cabin feature 컬럼 분포를 보게 되면, 너무 많은 선실 정보를 가지고 있게 된다.
따라서, 선실정보 첫 글자만 추출하여 너무 세분화된 데이터를 가공해보자.
titanic_df['Cabin'].value_counts()
## Output
N 687
C23 C25 C27 4
G6 4
B96 B98 4
C22 C26 3
...
E34 1
C7 1
C54 1
E36 1
C148 1
Name: Cabin, Length: 148, dtype: int64
titanic_df['Cabin'] = titanic_df['Cabin'].str[:1]
titanic_df['Cabin'].value_counts()
## Output
N 687
C 59
B 47
D 33
E 32
A 15
F 13
G 4
T 1
Name: Cabin, dtype: int64
이번에는 성별과 생존 간의 관계
를 살펴보자.
seaborn을 이용하여 barplot을 아래와 같이 그려보자.
sns.barplot(x='Sex', y='Survived', data=titanic_df)
이를 조금 더 세분화 해보면 x 축을 선박 등급, y를 생존여부로 놓고 각 선박 등급일 때 성별도 같이 보면 아래와 같다.
sns.barplot(x='Pclass', y='Survived', hue='Sex', data=titanic_df)
또한, 나이에 따라서도 생존률이 어떻게 되는지 확인해보려고 하는데
나이는 연속형 값이여서 이를 카테고리화 해보자.
# 입력 age에 따라 구분값을 반환하는 함수 설정. DataFrame의 apply lambda식에 사용
def get_category(age):
cat = ''
if age <= -1: cat = 'Unknown'
elif age <=5: cat = 'Baby'
elif age <=12: cat = 'Child'
elif age <=18: cat = 'Teenager'
elif age <=25: cat = 'Student'
elif age <=35: cat = 'Young Adult'
elif age <=60: cat = 'Adult'
else: cat = 'Elderly'
return cat
group_names = ['Unknown', 'Baby', 'Child', 'Teenager', 'Student', 'Young Adult', 'Adult', 'Elderly']
titanic_df['Age_cat'] = titanic_df['Age'].apply(lambda x: get_category(x))
# 막대그래프 크기 figure를 더 크게 설정
plt.figure(figsize=(10,6))
sns.barplot(x='Age_cat', y='Survived', hue='Sex', data=titanic_df, order=group_names)
학습 데이터와 테스트 데이터를 분리하고 각 알고리즘 별로 학습해보자.
y_titanic_df = titanic_df['Survived']
X_titanic_df = titanic_df.drop('Survived', axis=1, inplace=False)
X_titatic_df = transform_feature(X_titanic_df)
X_train, X_test, y_train, y_test=train_test_split(X_titanic_df, y_titanic_df, test_size=0.2, random_state=11)
# 결정트리, RandomForest, 로지스틱 회귀를 위한 사이킷런 클래스 생성
dt_clf = DecisionTreeClassifier(random_state=11)
rf_clf = RandomForestClassifier(random_state=11)
lr_clf = LogisticRegression(solver='liblinear')
# DecisionTreeClassifier 학습/예측/평가
dt_clf.fit(X_train, y_train)
dt_pred = dt_clf.predict(X_test)
print('DecisionTreeClassifier 정확도: {0: .4f}'.format(accuracy_score(y_test, dt_pred)))
# RandomForestClassifier 학습/예측/평가
rf_clf.fit(X_train, y_train)
rf_pred = rf_clf.predict(X_test)
print('RandomForestClassifier 정확도: {0: .4f}'.format(accuracy_score(y_test, rf_pred)))
# LogisticRegression 학습/예측/평가
lr_clf.fit(X_train, y_train)
lr_pred = lr_clf.predict(X_test)
print('LogisticRegression 정확도: {0: .4f}'.format(accuracy_score(y_test, lr_pred)))
Output
DecisionTreeClassifier 정확도: 0.7877
RandomForestClassifier 정확도: 0.8547
LogisticRegression 정확도: 0.8659
cv= 5의 교차검증을 먼저 해보자.
from sklearn.model_selection import cross_val_score
scores = cross_val_score(dt_clf, X_titanic_df, y_titanic_df, cv=5)
for iter_count, accuracy in enumerate(scores):
print("교차검증 {0} 정확도: {1: .4f}".format(iter_count, accuracy))
print("평균 정확도: {0: .4f}".format(np.mean(scores)))
Output
교차검증 0 정확도: 0.7430
교차검증 1 정확도: 0.7753
교차검증 2 정확도: 0.7921
교차검증 3 정확도: 0.7865
교차검증 4 정확도: 0.8427
평균 정확도: 0.7879
GridSearchCV를 이용하여 하이퍼 파라미터를 최적화 해보자.
from sklearn.model_selection import GridSearchCV
parameters = {'max_depth':[2,3,5,10],
'min_samples_split':[2,3,5], 'min_samples_leaf':[1,5,8]}
grid_dclf = GridSearchCV(dt_clf, param_grid=parameters, scoring='accuracy', cv=6)
grid_dclf.fit(X_train, y_train)
print('GridSearchCV 최적 하이퍼 파라미터: ', grid_dclf.best_params_)
print('GridSearchCV 최고 정확도: {0: .4f}'.format(grid_dclf.best_score_))
best_dclf = grid_dclf.best_estimator_
# GridSearchCV의 최적 하이퍼 파라미터로 학습된 Estimator로 예측 및 평가 수행
result = best_dclf.predict(X_test)
accuracy = accuracy_score(y_test, result)
print('테스트 세트에서의 DecisionTreeClassifier 최고 정확도: {0: .4f}'.format(accuracy))
Output
GridSearchCV 최적 하이퍼 파라미터: {'max_depth': 3, 'min_samples_leaf': 5, 'min_samples_split': 2}
GridSearchCV 최고 정확도: 0.8019
테스트 세트에서의 DecisionTreeClassifier 최고 정확도: 0.8715
하이퍼파라미터 최적화를 통해서 정확도가 향상된 것을 확인할 수 있다.
Referrence