ML/사이킷런

사이킷런을 이용한 타이타닉 생존자 예측

야뤼송 2024. 2. 13. 11:15
반응형
사이킷런을 이용하여 타이타닉의 생존자 예측, 교차검증 및 GridSearchCV를 통한 하이퍼파라미터를 찾아본다.

 

 

1.타이타닉 데이터 분석 및 전처리

Kaggle에서 제공하는 타이타닉 생존자 예측하기에 앞서 제공된 타이타닉 데이터를 탐색하고 분석해보자.

 

먼저 타이타닉 데이터를 불러오면 데이터 셋에는 승객의 정보, 생존에 대한 정보가 들어있다.

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)

▶ Out

 

 

각 필드는 다음과 같은 의미를 가진다.

  • Passengerid: 탑승자 데이터 일련번호
  • survived: 생존 여부, 0 = 사망, 1 = 생존
  • Pclass: 티켓의 선실 등급, 1 = 일등석, 2 = 이등석, 3 = 삼등석
  • sex: 탑승자 성별
  • name: 탑승자 이름
  • Age: 탑승자 나이
  • sibsp: 같이 탑승한 형제자매 또는 배우자 인원수
  • parch: 같이 탑승한 부모님 또는 어린이 인원수
  • ticket: 티켓 번호
  • fare: 요금
  • cabin: 선실 번호
  • embarked: 중간 정착 항구 C = Cherbourg, Q = Queenstown, S = Southampton

 

타이타닉 데이터를  세부정보를 보면 총 891개의 row가 있으며 각 컬럼 별 데이터 타입 정보를 확인 할 수 있다.

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

▶ Out

### train 데이터 정보 ###  

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
None

 

 

데이터를 살펴보면 머신런닝을 위해 몇가지 데이터 작업이 필요한 것을 알 수 있다.

먼저 머신런닝에 필요하지 않은 컬럼이 존재한다. Name, Ticket, PassengerId 이 3개의 피처는 머신런닝에 필요 없는 컬럼이이므로 제거하기위한 함수를 생성한다.

# 머신러닝 알고리즘에 불필요한 피처 제거
def drop_features(df):
    df.drop(['PassengerId','Name','Ticket'], axis=1, inplace=True)
    return df

 

info() 메소드를 통해 확인해보니 Null인 데이터가 존재하는 피처가 존재하고 null 값을 다른 값으로 변환하는 함수를 생성한다.

# Null 처리 함수
def fillna(df):
    df['Age'].fillna(df['Age'].mean(), inplace=True)
    df['Cabin'].fillna('N', inplace=True)
    df['Embarked'].fillna('N', inplace=True)
    return df

 

마지막으로 레이블 인코딩을 통해 문자열을 숫자형으로 바꿔준다. 선실 번호, Cabin의 경우 알파벳과 숫자형로 구성되어 있으며 첫번째 알파벳만 남겨두고 레이블 인코딩을 하여 숫자형으로 변경해 준다.

# 레이블 인코딩
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

 

최종적으로 위의 3개의 함수를 수행하는 processing 함수를 생성하여 머신러닝을 위한 데이터 최종 가공 처리를 수행하도록 한다.

# 앞에서 설정한 Data Preprocessing 함수 호출
def transform_features(df):
    df = fillna(df)
    df = drop_features(df)
    df = format_features(df)
    return df

 

 

2. 생존자 예측

타이타닉 데이터를 로딩하고 feature 데이터 세트와 label 데이터 세트를 추출한다.

label 데이터 세트는 생존여부(Survivied)만 따로 추출한다. feature 데이터 세트는 생존여부(Survivied)만 제거하고 위에서 생성한 데이터 가공 함수를 호출하여 데이터를 만든다.

titanic_df = pd.read_csv('./titanic_train.csv')
y_titanic_df = titanic_df['Survived']
X_titanic_df= titanic_df.drop('Survived',axis=1, inplace=False)

X_titanic_df = transform_features(X_titanic_df)

 

이렇게 생성된 feature 데이터 세트와 label 데이터 세트는 아래와 같다.

print(X_titanic_df)

▶ Out

     Pclass  Sex        Age  SibSp  Parch     Fare  Cabin  Embarked
0         3    1  22.000000      1      0   7.2500      7         3
1         1    0  38.000000      1      0  71.2833      2         0
2         3    0  26.000000      0      0   7.9250      7         3
3         1    0  35.000000      1      0  53.1000      2         3
4         3    1  35.000000      0      0   8.0500      7         3
..      ...  ...        ...    ...    ...      ...    ...       ...
886       2    1  27.000000      0      0  13.0000      7         3
887       1    0  19.000000      0      0  30.0000      1         3
888       3    0  29.699118      1      2  23.4500      7         3
889       1    1  26.000000      0      0  30.0000      2         0
890       3    1  32.000000      0      0   7.7500      7         2

[891 rows x 8 columns]

 

print(y_titanic_df)

▶ Out

0      0
1      1
2      1
3      1
4      0
      ..
886    0
887    1
888    0
889    1
890    0
Name: Survived, Length: 891, dtype: int64

 

 

학습 데이터와 테스트 데이터 세트로 분리후 데이터의 shape을 보면 891개 중 80프로인 712개의 feature 데이터셋과 20프로인 179개의 taret 데이터셋이 생성된걸 확인할 수 있다.

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)

print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)

▶ Out

(712, 8) (179, 8) (712,) (179,)

 

 

학습 데이터세트로 학습(fit)을 수행하고 테스트 데이터를 이용하여 예측(predict)을 수행한다.

from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score

# 결정트리를 위한 사이킷런 Classifier 클래스 생성
dt_clf = DecisionTreeClassifier(random_state=11)

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

▶ Out

DecisionTreeClassifier 정확도: 0.7877

 

 

3. 교차검증

교차 검증을 이용하여 평균 정확도도 계산해보자.

(교차 검증에 대한 내용은  K폴드 교차 검증이란? 을 참고한다)

 

교차 검증을 직접 구현하여 예측한 정확도는 다음과 같다.

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]

        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)

▶ Out

교차 검증 0 정확도: 0.7542
교차 검증 1 정확도: 0.7809
교차 검증 2 정확도: 0.7865
교차 검증 3 정확도: 0.7697
교차 검증 4 정확도: 0.8202
평균 정확도: 0.7823

 

 

사이킷런에서 제공하는 cross_val_score() 함수를 적용하면 조금 더 쉽게 교차 검증을 이용하여 정확도를 예측할 수 있다.

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

▶ Out

교차 검증 0 정확도: 0.7430
교차 검증 1 정확도: 0.7753
교차 검증 2 정확도: 0.7921
교차 검증 3 정확도: 0.7865
교차 검증 4 정확도: 0.8427
평균 정확도: 0.7879

 

 

4. GridSearchCV

GridSearchCV를 이용하여 최적의 하이퍼 파라미터로 학습된 예측 및 평가 값도 구해보자

(GridSearchCV에 대한 내용은 GridSearchCV이란?을 참고한다.)

 

Decision Tree Classifer의 하이퍼 파라미터 중 max_depth, min_samples_split, min_samples_leaf  이 3개의 최적화된 값만 찾아본다. 이 3개 파라미터 값을 간단하게 알아보면 다음과 같다.

  • max_depth : 트리의 최대 깊이
  • min_samples_split : 노드를 분할하기 위한 최소한의 샘플 데이터수)
  • min_samples_leaf : 리프노드가 되기 위해 필요한 최소한의 샘플 데이터수
    (리프노드 : 자식노드가 없는 노드, 말단 노드라고도 한다)

 

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=5)
grid_dclf.fit(X_train, y_train)

print('GridSearchCV 최적 하이퍼 파라미터 : ', grid_dclf.best_params_)
print('GridSearchCV 최고 정확도: {0:.4f}'.format(grid_dclf.best_score_))

▶ Out

GridSearchCV 최적 하이퍼 파라미터 :  {'max_depth': 3, 'min_samples_leaf': 5, 'min_samples_split': 2}
GridSearchCV 최고 정확도: 0.7992

 

 

best_estimator_ 를 통해 최적 하이퍼 파라미터로  학습된 Estimator 값을 가져온다. 이렇게 학습된 값을 통해 다시 한번 예측한 결과를 가져오면 최적화 후 정확도가 최적화 하기 전 정확도보다 높은것을 확인할 수 있다.

best_dclf = grid_dclf.best_estimator_
# GridSearchCV의 최적 하이퍼 파라미터로 학습된 Estimator로 예측 및 평가 수행. 
dpredictions = best_dclf.predict(X_test)
accuracy = accuracy_score(y_test, dpredictions)
print('테스트 세트에서의 DecisionTreeClassifier 정확도 : {0:0.4f}'.format(accuracy))

▶ Out

테스트 세트에서의 DecisionTreeClassifier 정확도 : 0.8715

 

 

반응형