컴공생 누르지 마세요! 컴공생 울어요.

[ML] HA2 part1 (2) RandomForest with Titanic dataset 본문

STUDY/기계학습

[ML] HA2 part1 (2) RandomForest with Titanic dataset

당도최고치악산멜론 2022. 12. 19. 15:49

📢 학교 수업에서 수행한 과제입니다.

 

이번 게시글에서는 titanic dataset에 대해 Random Forest 모델을 학습시켜 볼 것이다.

구글 코랩에서 코드를 작성 및 실행하였으며, 전체 코드는 지난 게시글을 참고하라.

 

  • 지난 게시글

[ML] HA2 part1 (1) Decision trees with Breast cancer dataset

https://kwonppo.tistory.com/38

 

[ML] HA2 part1 (1) Decision trees with Breast cancer dataset

HA2 part1은 'Decision trees with Breast cancer dataset'과 'RandomForest with Titanic dataset' 두 가지로 이루어져 있다. 이번 게시글에서는 우선 Decision trees에 대해 다룰 것이다. 구글 코랩에서 코드를 작성 및 실행

kwonppo.tistory.com


그럼 우선 titanic dataset을 import한다.

!wget --no-check-certificate 'https://docs.google.com/uc?export=download&id=1Z-IGKwjJ2z-tzJUFa9pWmG3BdMULbTqm' -O titanic.csv

그 다음으로 데이터 preprocessing을 진행해준다.

print('\nNull Values in data \n{}'.format(df2.isnull().sum()))

print('\nDuplicated values in data {}'.format(df2.duplicated().sum()))
# Preprocess Embarked column

print('Embarkation per ports \n{}'.format(df2['Embarked'].value_counts()))

# since the most common port is Southampton the chances are that the missing one is from there
df2['Embarked'].fillna(value='S', inplace=True)

print('Embarkation per ports after filling \n{}'.format(df2['Embarked'].value_counts()))
# Preprocess Age column

mean_age_miss = df2[df2["Name"].str.contains('Miss.', na=False)]['Age'].mean().round()
mean_age_mrs = df2[df2["Name"].str.contains('Mrs.', na=False)]['Age'].mean().round()
mean_age_mr = df2[df2["Name"].str.contains('Mr.', na=False)]['Age'].mean().round()
mean_age_master = df2[df2["Name"].str.contains('Master.', na=False)]['Age'].mean().round()

print('Mean age of Miss. title {}'.format(mean_age_miss))
print('Mean age of Mrs. title {}'.format(mean_age_mrs))
print('Mean age of Mr. title {}'.format(mean_age_mr))
print('Mean age of Master. title {}'.format(mean_age_master))

def fill_age(name_age):
    
    name = name_age[0]
    age = name_age[1]
    
    if pd.isnull(age):
        if 'Mr.' in name:
            return mean_age_mr
        if 'Mrs.' in name:
            return mean_age_mrs
        if 'Miss.' in name:
            return mean_age_miss
        if 'Master.' in name:
            return mean_age_master
        if 'Dr.' in name:
            return mean_age_master
        if 'Ms.' in name:
            return mean_age_miss
    else:
        return age

df2['Age'] = df2[['Name', 'Age']].apply(fill_age,axis=1)
# Preprocess Cabin column
df2['Cabin'] = pd.Series(['X' if pd.isnull(ii) else ii[0] for ii in df2['Cabin']])

print('Mean Fare of Cabin B {}'.format(df2[df2['Cabin']=='B']['Fare'].mean()))
print('Mean Fare of Cabin C {}'.format(df2[df2['Cabin']=='C']['Fare'].mean()))
print('Mean Fare of Cabin D {}'.format(df2[df2['Cabin']=='D']['Fare'].mean()))
print('Mean Fare of Cabin E {}'.format(df2[df2['Cabin']=='E']['Fare'].mean()))

def reasign_cabin(cabin_fare):
    
    cabin = cabin_fare[0]
    fare = cabin_fare[1]
    
    if cabin=='X':
        if (fare >= 113.5):
            return 'B'
        if ((fare < 113.5) and (fare > 100)):
            return 'C'
        if ((fare < 100) and (fare > 57)):
            return 'D'
        if ((fare < 57) and (fare > 46)):
            return 'D'
        else:
            return 'X'
    else:
        return cabin
      
df2['Cabin'] = df2[['Cabin', 'Fare']].apply(reasign_cabin, axis=1)
# Check again if any col holds NULL
print('\nNull Values in data \n{}'.format(df2.isnull().sum()))
# Lastly, change the categorical features into numerical values

categories = {"female": 1, "male": 0}
df2['Sex']= df2['Sex'].map(categories)

categories = {"S": 1, "C": 2, "Q": 3}
df2['Embarked']= df2['Embarked'].map(categories)

categories = {"X": 1, "C": 2, "E": 3, "G": 4, "D": 5, "A": 6, "B": 7, "F": 8, "T": 9}
df2['Cabin'] = df2['Cabin'].map(categories)
# Drop unnecessary columns

# dropping columns
df2 = df2.drop(['Name','Ticket','PassengerId'], axis=1)

이제 전처리를 완료하였다. 데이터 형태를 확인해보자.

df2.head()

본격적인 training 전, dataset을 train set과 test set으로 나눠준다.

X = df2[['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Cabin', 'Embarked']]
y = df2['Survived']

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(X, y, test_size= 0.2, random_state=0)

그 다음, data를 normalize 하기 위해 StandardScaler function을 사용한다.

from sklearn.preprocessing import StandardScaler
def scaler_samples(train_X,test_X):
  scaler = StandardScaler()
  train_X = scaler.fit_transform(train_X)
  test_X = scaler.transform(test_X)

  return train_X, test_X

x_train, x_test = scaler_samples(x_train, x_test)

그럼 이제 본격적으로 preprocessed titanic dataset에 대해 Random Forest model을 학습해보자. 주어진 input feature를 통해 해당 passenger가 살 수 있는지 없는지를 predict하는 모델을 만들 것이다.

이때, n_estimator = 20, criterion = "entropy"를 사용하였다.

from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=20, criterion="entropy", max_depth=100, min_samples_split=2, max_features="sqrt", random_state=0)

clf.fit(x_train, y_train)

이제 fit한 모델에 대해 accuracy와 confusion matirx를 확인해보자.

from sklearn.metrics import accuracy_score

y_pred = clf.predict(x_test)
acc = accuracy_score(y_test, y_pred)

print("Accuracy: ", acc)

from sklearn.metrics import confusion_matrix

confusion_matrix(y_test, y_pred)

이제 importance score 기반 feature ranking을 확인해보자.

import seaborn as sns
import matplotlib.pyplot as plt

feature_imp = pd.Series(clf.feature_importances_, index=X.columns).sort_values(ascending=False)

plt.figure(figsize=(10,6))
sns.barplot(x=feature_imp, y=feature_imp.index)

# Add labels to graph
plt.xlabel('Feature Importance Score')
plt.ylabel('Features')
plt.title("Feature Rankings")
plt.tight_layout()

Age, Fare, Sex가 more important feature인 것을 확인할 수 있다.

 

그럼 이제 Grid Search를 이용하여 Hyperparameter tuning을 수행해보자.

from sklearn.model_selection import GridSearchCV

param_grid = {'n_estimators': [20, 50, 100, 200],
              'criterion': ['gini', 'entropy']}

grid = GridSearchCV(RandomForestClassifier(), param_grid, refit=True, verbose=3)

grid.fit(x_train, y_train)

tuning 결과를 확인해보자.

# the best parameters
print(grid.best_params_)

# the model accuracy
grid_pred = grid.predict(x_test)
print("Accuracy: {}".format(accuracy_score(y_test, grid_pred)))

# the confusion matrix
confusion_matrix(y_test, grid_pred)

그럼 이제 hyperparameter tuning 전후 performance를 비교해보자.

 

(1) Accuracy 비교

튜닝 전의 accuracy: 0.8156424581005587

튜닝 후의 accuracy: 0.8268156424581006

튜닝 후 accuracy가 소폭 증가했음을 알 수 있다.

 

(2) Confusion matrix 비교

튜닝 전의 confusion matrix: array([[99, 11], [22, 47]])

튜닝 후의 confusion matrix: array([[98, 12], [19, 50]])

정답 클래스가 0인 경우에 대해서는 예측 클래스가 정답 클래스와 같은 표본의 수가 1 줄어들었지만, 정답 클래스가 1인 경우에 대해서는 예측 클래스가 정답 클래스와 같은 표본의 수가 3 늘었음을 알 수 있다.

 

따라서 hyperparameter tuning을 통해 model performance가 향상되었다고 볼 수 있다.

Comments