안 쓰던 블로그

사이킷런 - 타이타닉 생존자 ML 예측 구현하기 본문

머신러닝/머신러닝

사이킷런 - 타이타닉 생존자 ML 예측 구현하기

proqk 2020. 12. 7. 15:56
반응형

www.kaggle.com/c/titanic

 

Titanic: Machine Learning from Disaster

Start here! Predict survival on the Titanic and get familiar with ML basics

www.kaggle.com

캐글에서 머신러닝 입문자에게 제공하는 타이타닉 데이터 세트로 타이타닉 생존자 ML 예측을 구현한다


불러오기

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

titanic_df = pd.read_csv('./titanic_train.csv')
titanic_df.head(3)

Passengerid: 탑승자 데이터 일련번호

survived: 생존 여부, 0 = 사망, 1 = 생존

Pclass: 티켓의 선실 등급, 1 = 일등석, 2 = 이등석, 3 = 삼등석

sex: 탑승자 성별

name: 탑승자 이름

Age: 탑승자 나이

sibsp: 같이 탑승한 형제자매 또는 배우자 인원수

parch: 같이 탑승한 부모님 또는 어린이 인원수

ticket: 티켓 번호

fare: 요금

cabin: 선실 번호

embarked: 중간 정착 항구 C = Cherbourg, Q = Queenstown, S = Southampton

 

NULL값과 데이터 타입 알아보기

print('\n ### train 데이터 정보 ###  \n')
print(titanic_df.info())

NULL값은 머신러닝에서 허용되지 않기 때문에 대체해야 한다

NULL값이 있는 항목인 Age, Cabin, Embarked에 대해 처리해 줄 것이다

 

또한 object 컬럼도 통일해 주거나 필요없으면 드랍을 하고, 카테고리성 컬럼은 레이블을 해 준다

 

NULL값 처리

titanic_df['Age'].fillna(titanic_df['Age'].mean(),inplace=True)
titanic_df['Cabin'].fillna('N',inplace=True)
titanic_df['Embarked'].fillna('N',inplace=True)

print('데이터 세트 Null 값 갯수 ',titanic_df.isnull().sum().sum())

fillna: 결측값을 대체하는 메소드

Age칼럼 자체를 Age의 평균값으로 업데이트한다

Cabin과 Embarked는 N으로 업데이트한다

 

isnull().sum()을 하면 각 컬럼 별로 NULL 개수가 나오고, 거기에 sum()을 하면 모든 컬럼에 대한 값이 나온다

 

object값 처리

print(' Sex 값 분포 :\n',titanic_df['Sex'].value_counts())
print('\n Cabin 값 분포 :\n',titanic_df['Cabin'].value_counts())
print('\n Embarked 값 분포 :\n',titanic_df['Embarked'].value_counts())

Cabin값 분포를 보면 N값이 많다. 즉, NULL이 많다

또한 C23 C24 C27처럼 여러 값이 들어간 타입이 있다

맨 앞의 등급만 분리하여 정리한다

 

titanic_df['Cabin'] = titanic_df['Cabin'].str[:1]
print(titanic_df['Cabin'].head(3))
titanic_df['Cabin'].value_counts()

여기서 주의할 점은 앞 자리 하나만 가져오기 위해서 그냥 [:1]을 쓰면 안 된다

[:1]만 하면 또 다른 필터링을 하겠다는 의미이기 때문에 .str[:1]로 string이라고 표시해 주어야 맞다

 

데이터 구성 확인

성별에 따른 생존자 확인

titanic_df.groupby(['Sex','Survived'])['Survived'].count()

성별 별로 생존값을 확인한다

Sex, Survived 컬럼으로 group을 만들어서 Survived 컬럼에 대해 개수를 센다

 

sns.barplot(x='Sex', y = 'Survived', data=titanic_df)

barplot으로 그래프로 확인해 본다

데이터프레임을 인자로 넣으면 x와 y에 해당하는 컬럼을 자동으로 찾는다

 

성별과 선실 등급에 따른 생존자 확인

sns.barplot(x='Pclass', y='Survived', hue='Sex', data=titanic_df)

선실 등급에 따른 성별 별 생존값도 확인해 본다

hue에 해당되는 컬럼까지 같이 비교한 그래프를 출력한다

 

나이에 따른 생존자 확인

# 입력 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

# 막대그래프의 크기 figure를 더 크게 설정 
plt.figure(figsize=(10,6))

#X축의 값을 순차적으로 표시하기 위한 설정 
group_names = ['Unknown', 'Baby', 'Child', 'Teenager', 'Student', 'Young Adult', 'Adult', 'Elderly']

# lambda 식에 위에서 생성한 get_category( ) 함수를 반환값으로 지정. 
# get_category(X)는 입력값으로 'Age' 컬럼값을 받아서 해당하는 cat 반환
titanic_df['Age_cat'] = titanic_df['Age'].apply(lambda x : get_category(x))
sns.barplot(x='Age_cat', y = 'Survived', hue='Sex', data=titanic_df, order=group_names)
titanic_df.drop('Age_cat', axis=1, inplace=True)

Age_cat 컬럼을 만들고 apply에 람다식을 써서 함수에 따른 결과값을 리턴받아오도록 한다

성별 별로 barplot을 그리는데 group_names 순서에 맞추어 정렬한다

사용한 Age_cat 컬럼을 다시 드랍한다

 

인코딩

from sklearn import preprocessing

def encode_features(dataDF):
    features = ['Cabin', 'Sex', 'Embarked']
    for feature in features:
        le = preprocessing.LabelEncoder()
        le = le.fit(dataDF[feature])
        dataDF[feature] = le.transform(dataDF[feature])
        
    return dataDF

titanic_df = encode_features(titanic_df)
titanic_df.head()

features: 인코딩을 할 세 개의 컬럼을 추출한다

각 컬럼을 루프를 돌면서 LabelEncoder 객체를 만들고, fit과 transform으로 레이블 인코딩을 한다음에 데이터프레임을 리턴한다

 

코드 정리

from sklearn.preprocessing import LabelEncoder

# Null 처리 함수
def fillna(df):
    df['Age'].fillna(df['Age'].mean(),inplace=True)
    df['Cabin'].fillna('N',inplace=True)
    df['Embarked'].fillna('N',inplace=True)
    df['Fare'].fillna(0,inplace=True)
    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_features(df):
    df = fillna(df)
    df = drop_features(df)
    df = format_features(df)
    return df

앞서 코드로 썼던 NULL처리 부분을 다른 곳에서도 호출할 수 있도록 함수 형태로 바꾼다

Passengerid, Name, Ticket 속성은 불필요하므로 제거한다

레이블 인코딩(Cabin의 데이터에서 맨 앞만 떼는 것, 인코딩) 부분도 하나의 함수 형태로 묶는다

그리고 세 개의 함수들을 한 번에 호출하는 transform_features 함수를 만든다

 

학습/예측/평가

# 원본 데이터를 재로딩 하고, feature데이터 셋과 Label 데이터 셋 추출. 
titanic_df = pd.read_csv('./titanic_train.csv')
y_titanic_df = titanic_df['Survived']
X_titanic_df= titanic_df.drop('Survived',axis=1)

X_titanic_df = transform_features(X_titanic_df)

원본 데이터를 재로딩하고 feature 데이터 세트와 Label 세트를 추출한다

 

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test=train_test_split(X_titanic_df, y_titanic_df, test_size=0.2, random_state=11)

 

추출된 feature 데이터 세트와 Label 세트를 tran_test_split 함수에 넣어서, 학습 데이터 세트와 테스트 데이터 세트로 분리한다

 

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# 결정트리, Random Forest, 로지스틱 회귀를 위한 사이킷런 Classifier 클래스 생성
dt_clf = DecisionTreeClassifier(random_state=11)
rf_clf = RandomForestClassifier(random_state=11)
lr_clf = LogisticRegression()

# 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)))

결정 트리, Random Forest, 로지스틱 회귀 세 개 알고리즘으로 학습/예측/평가하여 모델들을 상호 평가해 본다

 

교차 검증

from sklearn.model_selection import KFold

def exec_kfold(clf, folds=5):
    # 폴드 세트가 5개인 KFold객체를 생성, 폴드 수만큼 예측결과 저장을 위한  리스트 객체 생성.
    kfold = KFold(n_splits=folds)
    scores = []
    
    # KFold 교차 검증 수행. 
    for iter_count , (train_index, test_index) in enumerate(kfold.split(X_titanic_df)):
        # X_titanic_df 데이터에서 교차 검증별로 학습과 검증 데이터를 가리키는 index 생성
        X_train, X_test = X_titanic_df.values[train_index], X_titanic_df.values[test_index]
        y_train, y_test = y_titanic_df.values[train_index], y_titanic_df.values[test_index]
        
        # Classifier 학습, 예측, 정확도 계산 
        clf.fit(X_train, y_train) 
        predictions = clf.predict(X_test)
        accuracy = accuracy_score(y_test, predictions)
        scores.append(accuracy)
        print("교차 검증 {0} 정확도: {1:.4f}".format(iter_count, accuracy))     
    
    # 5개 fold에서의 평균 정확도 계산. 
    mean_score = np.mean(scores)
    print("평균 정확도: {0:.4f}".format(mean_score)) 
# exec_kfold 호출
exec_kfold(dt_clf , folds=5)

폴드 세트가 5개인 kfold 객체를 만들고 split하여 학습과 테스트용 인덱스가 만든다

그리고 다시 Classifier 학습, 예측, 정확도를 계산하고 평균 정확도를 계산한다

이 코드에서는 일단 DecisionTreeClassifier(결정트리)만 kfold를 통해서 검증을 하고 있다

 

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)))

cross_val_score로 5번의 교차 검증을 시행한 정확도를 구한다

 

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=5)
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로 예측 및 평가 수행. 
dpredictions = best_dclf.predict(X_test)
accuracy = accuracy_score(y_test , dpredictions)
print('테스트 세트에서의 DecisionTreeClassifier 정확도 : {0:.4f}'.format(accuracy))

GridSearchCV를 사용하여 dt_clf의 교차 검증과 하이퍼 파라미터 구하기를 동시에 수행한다

먼저 max_depth, min_samples_split, min_samples_leaf 파라미터 값을 결정한다

GridSearchCV 객체를 만들고 DecisionTreeClassifier와 순차적으로 수행할 파라미터들, 성능을 측정할 매트릭은 정확도, 폴드 세트는 5개로 한다

 

GridSearchCV의 refit값이 True면(기본 True) 최적의 하이퍼 파라미터로 dt_clf를 다시 학습한다

그렇게 학습된 estimator는 best_estimator_ 라는 속성으로 찾을 수 있다

위의 코드에서는 그 값을 best_dclf 변수에 저장했다

 

best_dclf로 다시 예측하고 정확도를 확인하면, 최종 정확도는 0.8715가 나왔다


정리

머신 러닝 지도 학습 프로세스

데이터 전처리->데이터 세트 분리->모델 학습 및 검증 평가->예측 수행->평가

 

데이터 전처리

  -데이터 클린징

  -결손값 처리(Null/NAN 처리)

  -데이터 인코딩(레이블, 원-핫 인코딩)

  -데이터 스케일링

  -이상치 제거

  -Feature 선택, 추출 및 가공

 

데이터 세트 분리

  -학습 데이터/테스트 데이터 분리

 

모델 학습 및 검증 평가

  -알고리즘 학습

  -교차 검증, cross_val_score(), GridSearchCV

 

예측 수행

  -테스트 데이터로 예측 수행

 

평가

  -예측 평가


'파이썬 머신러닝 완벽가이드'를 정리한 내용입니다

반응형
Comments