본문 바로가기

Theory/MachineLearning

결정트리를 이용한 타이타닉 생존자 예측

타이타닉 생존자 예측이라는 주재를 가지고 신경망으로 분류를 했던 적이 있습니다. 당시엔 Keras를 사용했는데요. 이번에는 결정트리 Decision Tree 기법을 이용하려고 합니다. 그리고 사이킷런 Scikit Learn을 이용할 거구요^^ 먼저 데이터는 이전에 했던 [Keras] 타이타닉 생존자 예측에서 사용한 엑셀로된 데이터 입니다.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

raw_data = pd.read_excel('titanic.xls')
raw_data.info()

필요한 모듈과 데이터를 읽었습니다.

데이터가 1300개 정도로 보이지만, 중요 데이터인 age가 null이 있어서 살짝 손을 봐줘야 합니다.

tmp = []
for each in raw_data['sex']:
    if each == 'female':
        tmp.append(1)
    elif each == 'male':
        tmp.append(0)
    else:
        tmp.append(np.nan)

raw_data['sex'] = tmp

raw_data['survived'] = raw_data['survived'].astype('int')
raw_data['pclass'] = raw_data['pclass'].astype('float')
raw_data['sex'] = raw_data['sex'].astype('float')
raw_data['sibsp'] = raw_data['sibsp'].astype('float')
raw_data['parch'] = raw_data['parch'].astype('float')
raw_data['fare'] = raw_data['fare'].astype('float')

raw_data = raw_data[raw_data['age'].notnull()]
raw_data = raw_data[raw_data['sibsp'].notnull()]
raw_data = raw_data[raw_data['parch'].notnull()]
raw_data = raw_data[raw_data['fare'].notnull()]

raw_data.info()

이렇게 필요한 데이터들은 숫자로 변경하고, NaN이 아닌 데이터들만 가져오는 겁니다. 저기처럼 다 notnull() 처리할 필요 없이 사실 age 컬럼에만 해주면 되는데.. 어쩌다 저렇게 네 줄짜리가 되었는지.ㅠㅠ. 아마 코드 돌려막기와 확인하기 귀차니즘 때문이겠죠~

그리고 나면 저렇게 데이터가 만들어 집니다. 흠.. 그러고 보니... age의 데이터보다 하나가 더 적네요... 그렇다면 나머지 어딘가에도 null이 있었다는 거군요^^

데이터 head()를 보면 저렇습니다.~

train_pre = raw_data[['pclass','sex','age','sibsp','parch','fare']]
train_pre.head()

필요한 컬럼만 다시 가져옵니다. 변수 이름 작업법이라는 교육이 있으면 꼭 들어야겠습니다. ㅠㅠ.

이제... 이렇게 만들고 난 후~

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(train_pre, raw_data[['survived']], test_size=0.1, random_state=13)

흠 훈련용 데이터와 테스트용 데이터로 나눕니다. sklearn에서 제공하는 train_test_split을 사용했고, 세상에서 가장 완벽한 숫자인 13[각주:1]을 random_state로 결정했습니다.

X_train = X_train.reset_index()
X_train = X_train.drop(['index'], axis=1)

X_test = X_test.reset_index()
X_test = X_test.drop(['index'], axis=1)

y_train = y_train.reset_index()
y_train = y_train.drop(['index'], axis=1)

y_test = y_test.reset_index()
y_test = y_test.drop(['index'], axis=1)

그리고 가장 마음에 안 드는 코드인 인덱스를 좀 정리하는 곳입니다. 생각해보니... 데이터를 나누기 전에 저걸하고, 나누면 저렇게 네 번 복사한듯 한 무식함은 없을텐데.ㅠㅠ. 뭐 아무튼 그러합니다.

from sklearn.tree import DecisionTreeClassifier
tree_clf = DecisionTreeClassifier(max_depth=3, random_state=13)
tree_clf.fit(X_train, y_train)
print('Score: {}'.format(tree_clf.score(X_train, y_train)))

이제.. 드디어 결정트리 DecisionTreeClassifier 분류기를 사용합니다. depth는 3단계 정도로 보고... random_state는 가장 완벽하다는 그 숫자 13을 사용합니다.^^. 아무튼~ 훈련 성과를 볼까요?

80%가 넘네요... 그냥 만족할렵니다.^^. 

from sklearn.tree import export_graphviz

export_graphviz(
        tree_clf,
        out_file="titanic.dot",
        feature_names=['pclass', 'sex', 'age', 'sibsp', 'parch', 'fare'],
        class_names=['Unsurvived','Survived'],
        rounded=True,
        filled=True
    )

import graphviz
with open("titanic.dot") as f:
    dot_graph = f.read()
dot = graphviz.Source(dot_graph)
dot.format = 'png'
dot.render(filename='titanic_tree', directory='images/decision_trees', cleanup=True)
dot

이제 sklearn에서 Decision Tree를 사용할때의 가장 큰 장점인... 트리 구조를 보겠습니다.

와우~ 제일 상층부에서... 성별이 여성이면 오른쪽으로 ... 선실 등급이 1 혹은 2등급이면 그 밑으로 두개가 있지만, 뭐 둘다 살아남는군요... ㅎㅎ^^ 여하튼... 결정트리와 같은 알고리즘의 장점은 역시 저렇게 결정되는 과정[각주:2]을 쉽게 눈으로 확인할 수 있다는 거죠.

from sklearn.metrics import accuracy_score

y_pred = tree_clf.predict(X_test)
print("Test Accuracy is ", accuracy_score(y_test, y_pred)*100)

이제 테스트 데이터 셋에 적용해볼까요?

84.76%군요... max_depth를 높이면 과적합 위험성이 있죠.. 이 정도 선에서 마무리하는 것고 좋겠습니다. 사실.. recall이나 precision도 확인해야겠지만... 오늘은 여기까지^^

# pclass, sex, age, sibsp, parch, fare
dicaprio = [3., 0., 19., 0., 0., 5.]
winslet = [1., 1., 17., 1., 2., 100.]

def isSurvived(name, person):
    isSurvive = 'not survived' if tree_clf.predict([person])[0] == 0 else 'survived'
    print(name, ' is ', isSurvive, 
          ' --> ', max(tree_clf.predict_proba([person])[0]))
    
isSurvived('Dicaprio', dicaprio)
isSurvived('Winslet', winslet)

아... 디카프리오나 윈슬릿의 데이터를 넣어봐야죠~ 

흠... 디카프리오 형님 생존하지 못할 확율이 87.5%, 윈슬릿의 생존확률이 97.58%가 나오는군요... 뭐 아무튼.. Toy 프로젝트니까요...^^

  1. 양웬리의 13함대 : https://namu.wiki/w/%EC%96%91%20%EC%9B%AC%EB%A6%AC%20%ED%95%A8%EB%8C%80 [본문으로]
  2. 화이트박스모델이라고 한다. 반대로 예측되는 과정이나 그 결과를 설명할 수 없는 신경망과 같은 알고리즘을 블랙박스모델이라고 한다. [본문으로]
반응형