오늘은 titanic 데이터를 갖고 decision tree 모델을 공부해봤다.
머신러닝 공부할 때 kaggle은 꼭 보는 것이 좋다. 워낙 훌륭하신 분들이 많아.. 필사를 해보는 것 만으로도 아주 많은 도움이 된다.
import numpy as np
import pandas as pd
import re
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.metrics import accuracy_score
from sklearn.model_selection import KFold, cross_val_score, train_test_split
from sklearn.tree import DecisionTreeClassifier
갖고 있는 타이타닉 데이터가 캐글에 올라와있는거랑 살짝 달라서 캐글에 있는걸로 다시 다운받았다. 통으로 된 csv 파일을 train, test 구분하는건 train_test_split으로 구분하면 될 것 같은데 아직 방법을 잘 모르겠어서 다른 것들 보면서 공부할 예정!
train = pd.read_csv('titanic_train.csv')
test = pd.read_csv('titanic_test.csv')
PassengerId = test['PassengerId']
train.head()
PassengerId, Survived, Pclass 등의 컬럼들은 숫자로 되어있지만 Name, Sex와 같은 컬럼들은 object형태이기 때문에 전처리를 통해서 int타입으로 바꿔줘야 한다.
print(train.info())
print([(cab,type(cab)) for cab in train.Cabin.unique()])
특히 Cabin 컬럼에서 null값이 많은데 이런 null값들도 전처리로 보정이 필요하다. unique 함수로 cabin컬럼에 있는 데이터들의 타입을 뽑아보면 값이 있는 컬럼들은 string이고 null 값은 데이터타입이 float이다.
#원본 데이터 유지를 위해 복사본 생성
original_train = train.copy()
# train, test 합친 full data생성
full_data = [train, test]
# Cabin컬럼 null값 보정
train['Has_Cabin'] = train["Cabin"].apply(lambda x: 0 if type(x) == float else 1)
test['Has_Cabin'] = test["Cabin"].apply(lambda x: 0 if type(x) == float else 1)
# SibSp and Parch을 결합해 FamilySize feature 새로 생성
for dataset in full_data:
dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1
# FamilySize로 IsAlone feature 새로 생성
for dataset in full_data:
dataset['IsAlone'] = 0
dataset.loc[dataset['FamilySize'] == 1, 'IsAlone'] = 1
# Embarked column null값 제거(fillna함수)
for dataset in full_data:
dataset['Embarked'] = dataset['Embarked'].fillna('S') --null값은 'S'로 대체
# are column null값 제거(fillna함수)
for dataset in full_data:
dataset['Fare'] = dataset['Fare'].fillna(train['Fare'].median()) --null값은 중앙값으로 대체
# Age column null값 제거
for dataset in full_data:
age_avg = dataset['Age'].mean()
age_std = dataset['Age'].std()
age_null_count = dataset['Age'].isnull().sum()
age_null_random_list = np.random.randint(age_avg - age_std, age_avg + age_std, size=age_null_count)
# 오류 방지
dataset.loc[np.isnan(dataset['Age']), 'Age'] = age_null_random_list
dataset['Age'] = dataset['Age'].astype(int)
# passenger names으로 title 컬럼 생성
def get_title(name):
title_search = re.search(' ([A-Za-z]+)\.', name)
# If the title exists, extract and return it.
if title_search:
return title_search.group(1)
return ""
for dataset in full_data:
dataset['Title'] = dataset['Name'].apply(get_title)
# Group all non-common titles into one single grouping "Rare"
for dataset in full_data:
dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss')
dataset['Title'] = dataset['Title'].replace('Ms', 'Miss')
dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs')
for dataset in full_data:
# Mapping Sex
print(dataset.Sex.unique())
dataset['Sex'] = dataset['Sex'].map( {'female': 0, 'male': 1} ).astype(int)
# Mapping titles
title_mapping = {"Mr": 1, "Master": 2, "Mrs": 3, "Miss": 4, "Rare": 5}
dataset['Title'] = dataset['Title'].map(title_mapping)
dataset['Title'] = dataset['Title'].fillna(0)
# Mapping Embarked
dataset['Embarked'] = dataset['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int)
# Mapping Fare
dataset.loc[ dataset['Fare'] <= 7.91, 'Fare'] = 0
dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1
dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare'] = 2
dataset.loc[ dataset['Fare'] > 31, 'Fare'] = 3
dataset['Fare'] = dataset['Fare'].astype(int)
# Mapping Age
dataset.loc[ dataset['Age'] <= 16, 'Age'] = 0
dataset.loc[(dataset['Age'] > 16) & (dataset['Age'] <= 32), 'Age'] = 1
dataset.loc[(dataset['Age'] > 32) & (dataset['Age'] <= 48), 'Age'] = 2
dataset.loc[(dataset['Age'] > 48) & (dataset['Age'] <= 64), 'Age'] = 3
dataset.loc[ dataset['Age'] > 64, 'Age'] ;
한번에 돌리지 않으면 에러가 난다. 에러가 나면 다시 처음으로 돌아가서 titanic train, test 데이터부터 불러와주면 된다.
drop_elements = ['PassengerId', 'Name', 'Ticket', 'Cabin', 'SibSp']
train = train.drop(drop_elements, axis=1) #열에서 삭제
test = test.drop(drop_elements, axis=1)
train.head()
PassengerId, Name과 같이 필요 없는 컬럼들은 드롭하고 새로 만든 train data를 가져오면 처음과 달리 모든 컬럼이 숫자 형태로 바뀌었다. 이렇게 각 컬럼별로 코드를 매핑해줘야 모형을 적합시키기 수월해진다.
#최적의 max depth 찾기
cv = KFold(n_splits=10) # Desired number of Cross Validation folds
accuracies = list()
max_attributes = len(list(test))
depth_range = range(1, max_attributes + 1)
# Testing max_depths from 1 to max attributes
# Uncomment prints for details about each Cross Validation pass
for depth in depth_range:
fold_accuracy = []
tree_clf = DecisionTreeClassifier(max_depth = depth)
# print("Current max depth: ", depth, "\n")
for train_fold, valid_fold in cv.split(train):
f_train = train.loc[train_fold] # Extract train data with cv indices
f_valid = train.loc[valid_fold] # Extract valid data with cv indices
model = tree_clf.fit(X = f_train.drop(['Survived'], axis=1),
y = f_train["Survived"]) # We fit the model with the fold train data
valid_acc = model.score(X = f_valid.drop(['Survived'], axis=1),
y = f_valid["Survived"])# We calculate accuracy with the fold validation data
fold_accuracy.append(valid_acc)
avg = sum(fold_accuracy)/len(fold_accuracy)
accuracies.append(avg)
# print("Accuracy per fold: ", fold_accuracy, "\n")
# print("Average accuracy: ", avg)
# print("\n")
# Just to show results conveniently
df = pd.DataFrame({"Max Depth": depth_range, "Average Accuracy": accuracies})
df = df[["Max Depth", "Average Accuracy"]]
print(df.to_string(index=False))
타깃이 survived이므로 survived를 제외한 나머지 컬럼은 X변수로, survived는 y변수로 지정한다.
최적의 max_depth는 숫자를 바꿔가면서 일일이 찾아볼 수도 있지만 for문을 사용해서 여러 개의 decision tree를 만들고 각 tree별로 k겹 교차검증을 시행했을 때의 accuracy를 평균내서 가장 값이 높은 것으로 선택하면 된다.
돌려보면 max_depth가 3일 때 averge accuracy가 가장 좋다.
y_train = train['Survived']
x_train = train.drop(['Survived'], axis=1).values
x_test = test.values
tree_clf = DecisionTreeClassifier(criterion='entropy', max_depth=3, random_state=42)
tree_clf.fit(x_train, y_train)
y_pred = tree_clf.predict(x_test)
acc_decision_tree = round(tree_clf.score(x_train, y_train) * 100, 2)
acc_decision_tree
>>>83.16
max_depth=3으로 Decision Tree Classifier 모델을 만들었다.
train set의 정확도는 83.16%이다.
'파이썬 > 머신러닝' 카테고리의 다른 글
배깅(bagging) 기본 개념과 예시, 사이킷런 BaggingClassifier (0) | 2021.06.21 |
---|---|
랜덤 포레스트 원리와 구현 사이킷런 예제로 코드 실습해보기 (1) | 2021.06.19 |
캐글 heart 데이터로 EDA부터 로지스틱회귀, 트리모델 적합까지 총정리 (0) | 2021.06.17 |
결정트리(Decision Tree) , 엔트로피 개념과 시각화까지 (0) | 2021.06.13 |
Linear Regression 선형회귀 파이썬 코드 예제 (보스턴 주택 가격 csv 파일) (2) | 2021.06.08 |