"""
#### 이 커널은 [Diego Milla님의 결정트리](https://www.kaggle.com/dmilla/introduction-to-decision-trees-titanic-dataset)를 번역 및 요약한 커널입니다. 말투는 "~다."로 끝나는 점 양해해주세요! (+표시가 된 주제들은 이해를 위해 제가 덧붙였습니다! 참고해주세요)
#### This kernel is a translated version of @DiegoMilla 's "[Introduction to Decision Trees(Titanic dataset)](https://www.kaggle.com/dmilla/introduction-to-decision-trees-titanic-dataset)".


"""
"""
# 요약
#### 이 커널은 파이썬과 타이타닉 데이터 셋을 이용하여 결정 트리에 관하여 볼 것 입니다. 타이타닉 모델에서 가장 정확한 모델은 아니지만, 분류 트리를 어떻게 만들고, 시각화하며 이해할 수 있는지 볼 것입니다. 주로 다루어볼 주제들은 : 
- 데이터를 이용하여 결정 트리 학습
- 데이터셋 분석 및 처리 과정
- 결정트리에 관련된 특징들
- 지니 계수
- 교차 검증을 통한 최선의 나무 깊이 찾기
- 결정된 모델을 시각화하고 만들기

#### 입니다.
"""
"""
# 소개
#### 머신 러닝 알고리즘을 적용할 때, 우리는 어떤 문제를 해결할 건지를 중요하게 생각해야 한다. 우리는 이 문제들을 해결하기 위하여 고급 기술들(예를 들면 DeepLearning딥러닝 이나 EnsembleLearning앙상블 학습)을 이용하곤 한다. 하지만 이러한 고급 기술들에서도 복잡함/정확함 사이의 거래가 발생하기에 간단한 모델이 오히려 더 일반화를 잘 하는 경우도 발생한다.

#### 결정 트리는 데이터를 이해하는데 굉장한 도움을 줄 수 있다. 대표적인 예시로는 [sklearn documentation](https://scikit-learn.org/stable/modules/tree.html)에 있는 Iris flowers를 분류하는 문제를 들 수 있다. 여기서 볼 수 있듯이 결정 트리는 다른 알고리즘을 적용하기 전에 데이터를 확인해보는데 굉장히 유용하다.

#### 하지만 결정트리의 주요 단점으로는 과적합하는 경향성, 특징들 사이에서 관계를 잡지 못하거나, (보장할 수 없는) 탐욕 알고리즘을 사용한 다는 점이 있다. 랜덤 포레스트를 이용하는 것이 이러한 이슈들을 덜어 줄 수 있다.

#### 결정 트리에 대한 이 짧은 소개 후에 어떻게 타이타닉 문제에 적용하는지 보라. 먼저, 우리는 데이터셋을 정리하고 가장 관련있는 특징들을 잡아낼 것이다. 우리는 그 후에 과적합을 피하기 위해 최선의 트리 깊이를 찾아내고, 최종 모델을 일반화하고, 이 모델을 어떻게 시각화할 지 보여줄 것이다.
"""
"""
# 타이타닉 데이터셋 정렬 및 준비하기
#### 타이타닉 문제는 test 데이터셋에 있는 개개인들의 생존 여부를 판가름하는 것이다. 분류 트리에 도움을 주고자 데이터를 정리하고자 한다. 데이터를 정리해보고 인사이트를 얻어보자.
"""
# 분석을 위해 필요한 라이브러리들 import
import numpy as np
import pandas as pd
import re
import xgboost as xgb
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline

import plotly.offline as py
py.init_notebook_mode(connected=True)
import plotly.graph_objs as go
import plotly.tools as tls

#결정 트리 만드는데 필요한 라이브러리들 import
from sklearn import tree
from sklearn.metrics import accuracy_score
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from IPython.display import Image as PImage
from subprocess import check_call
from PIL import Image, ImageDraw, ImageFont

# 데이터 가져오기
train = pd.read_csv('../input/train.csv')
test = pd.read_csv('../input/test.csv')

# 결과값 넣을 test셋 준비
PassengerId = test['PassengerId']

# train 잠깐만 보면...
train.head(3)

"""
#### 데이터 셋들을 보니 survived는 이미 이진법 형식으로 나타나있지만 Name, Ticket이나 Cabin 같은 특징들은 이러한 형식으로 나타나있지 않는다. 이 형식을 전환하기 위해서는 존재하는 특징들에 합치거나 새롭게 만드는 방식으로 해결할 수 있다. 아래를 참고해보자.(Title 특징에는 [Sina](https://www.kaggle.com/sinakhorami/titanic-best-working-classifier), [Anisotropic](https://www.kaggle.com/arthurtok/introduction-to-ensembling-stacking-in-python), [Megan Risdal](https://www.kaggle.com/mrisdal/exploring-survival-on-the-titanic) 의 방식을 참고하였다.)

### + 분석 설명 추가
- Deal with null datasets(빈 데이터셋 처리) : 빈 데이터셋의 학습에 도움을 주지 못하므로 가능한 그 값을 예측하여 넣는 경우가 많다. 다음은 빈 데이터 값을 예측할 때 이용되는 방법론들을 나열한 것이다
    - average/mean : 평균으로 때려맞추기
    - quartile : 사분위수 내의 값 안에서 랜덤으로 고르게 > age 섹션 확인
    - median : 중위수 값으로 때려맞추기 > Fare 섹션 확인
    - 자명한 수 /임의의 수: 자명한 데이터들은 수 자체를 기입한다/예측이 어려운 경우 그냥 임의의 수를 넣어놓기도 한다. > (임의의 수 경우)Embarked 섹션 확인

"""
#주의 : 데이터 처리 과정은 Sina, Anisotropic, Megan Risdal 방식을 참고하여 만들어졌다.
# 학습 데이터 셋 : original_train
original_train = train.copy() # copy()함수로 데이터셋 복제
full_data = [train, test]

# 데이터셋 형성 및 Null Dataset 정리

# Has_Cabin 데이터셋 정리
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와 Parch의 데이터셋을 통해 FamilySize라는 새로운 데이터셋 생성
for dataset in full_data:
    dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1
# FamilySize를 통해 IsAlone이라는 새로운 데이터셋 생성
for dataset in full_data:
    dataset['IsAlone'] = 0
    dataset.loc[dataset['FamilySize'] == 1, 'IsAlone'] = 1
    
# Embarked의 Null 정리하기
for dataset in full_data:
    dataset['Embarked'] = dataset['Embarked'].fillna('S')
    
# Fare의 Null 정리하기
for dataset in full_data:
    dataset['Fare'] = dataset['Fare'].fillna(train['Fare'].median())

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

"""
### + Mapping 방식 정리
- Mapping(변환 작업) : 영어, 넓은 숫자 범위, 영어 글자 들로 널려진 데이터들을 숫자들로 제한시키면서 데이터의 예측을 용이하게 만든다. ex) embarked의 데이터는 C,S,R일 때 이를 숫자 1,2,3으로 변환하여 예측이 더 쉽고 빠르게 되도록 만들고자 한다.
    - 유무/남녀 차이처럼 binary한 특징은 0,1로 구분
    - 넓은 범위에 한정된 데이터 특징은 사분위수를 이용하여 0~3으로 구분
- 여기에서의 Mapping 정리
    - Has_Cabin - Cabin의 유무에 따라 0,1으로 정리
    - FamilySize, IsAlone - Sibsp. Parch를 통해 추리
    - Embarked - 승선 위치(S,C,Q)를 0,1,2로 정리
    - Fare, Age - 나이, 요금 데이터를 직접 이용하기보다는 사분위수로 구분하여 0~3의 범위로 한정함.
    - Sex - 남녀의 차이를 0,1로 구분
    - Title - 이름 자체에서 뽑을 수 있는 정보(Miss, Mrs)
"""
# Mapping 작업

# Define function to extract titles from passenger names
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
    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'] ;

# 의미있는 데이터(학습할 의향 의사가 표시된 데이터만 골라내기)
drop_elements = ['PassengerId', 'Name', 'Ticket', 'Cabin', 'SibSp']
train = train.drop(drop_elements, axis = 1)
test  = test.drop(drop_elements, axis = 1)
"""
# 처리한 데이터를 Pearson Correlation/Heatmap을 통해 시각화해보기

#### + 시각화 과정이 왜 필요한가?
#### 결정트리를 만들기 위해서는 여러가지 특징들과의 관계를 살펴보는 것이 필수적인데, 이를 통해서 가장 처음 특성(처음 데이터 분류를 가능하게 할 특성)을 고르기 위해서 필요하다.
"""
train.head(3)
"""
### + Pearson Correlation/Heatmap 이란?
#### 피어슨 상관계수(Pearson Correlation)은 두 변수 간의 선형 상관 관계를 계량화한 수치이며 -1~+1 사이의 값을 가진다. 절댓값을 통해 관계 정도를 파악할 수 있는데, 절댓값이 1에 가까울수록 강한 상관관계(상대적으로 상관 있는, 선형적인 관계)를 가짐을 알 수 있다.
#### 여기서 나오는 그래프는 피어슨 상관계수를 이용하여 나타낸 Heatmap으로, 데이터를 시각화할 때 자주 보게 되는 형태이다(라이브러리는 seaborn 이용). 중간 대각선을 기준으로 대칭적인 관계를 나타내므로 반으로 갈라서 한쪽만을 골라서 상관계수 개념을 이용해 파악하면 된다.
"""
colormap = plt.cm.viridis
plt.figure(figsize=(12,12))
plt.title('Pearson Correlation of Features', y=1.05, size=15)
sns.heatmap(train.astype(float).corr(),linewidths=0.1,vmax=1.0, square=True, cmap=colormap, linecolor='white', annot=True)
"""
이 heatmap은 각 특징의 예측도를 쉽계 가질 수 있어서 굉장히 유용하다. 여기서 Survived와 각 특징의 관계를 나타내는 가장 위쪽 줄을 보면 Sex와 Title이 강한 관계를 가짐을 알 수 있다 : 각각 0.54, 0.49 정도 보인다. 더불어 둘의 상관관계도 0.86으로 이 표 자체에서 가장 높다. 한번 이 둘의 특징을 더 자세히 살펴보자.
"""
"""
### Title(이름) VS Sex(성별)
#### 이 둘은 각각의 그룹들을 기본적인 통계를 계산함으로서 이 둘 자체와 둘의 특징을 알수 있다.
"""
# Title, Sex 각각 비교하기

train[['Title', 'Survived']].groupby(['Title'], as_index=False).agg(['mean', 'count', 'sum'])
# 여기서 MEAN : 생존 확률, COUNT : 전체 관측 숫자, SUM : 생존숫자
# title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5} 
train[['Sex', 'Survived']].groupby(['Sex'], as_index=False).agg(['mean', 'count', 'sum'])
# 여기서 MEAN : 생존 확률, COUNT : 전체 관측 숫자, SUM : 생존숫자
# sex_mapping = {{'female': 0, 'male': 1}
"""
#### 여기서 남자쪽(Sex 섹션의 1번)의 생존률(18.89%)과 Mr쪽(Title 섹션의 1번)으로 보아 Title이 Sex쪽보다 더 유리함을 알 수 있다. 왜냐하면 Title쪽이 Sex보다 더 많은 정보를 암시적으로 포함하기 때문이다. 이것을 증명하기 위해 이름별로 분류된 성별 정보로 파악해보자.
"""
#기존에 존재하는 original_train 데이터 셋을 통해서 Title 별로 분류된 Sex 분포를 확인해보자.
title_and_sex = original_train.copy()[['Name', 'Sex']]
title_and_sex['Title'] = title_and_sex['Name'].apply(get_title) #Title 섹션 생성
title_and_sex['Sex'] = title_and_sex['Sex'].map( {'female': 0, 'male': 1} ).astype(int) #Mapping 과정

title_and_sex[['Title', 'Sex']].groupby(['Title'], as_index=False).agg(['mean', 'count', 'sum']) #분류하기

"""
#### 여기서 볼 수 있듯이 Title은 동일한 Sex 특징의 정보를 포함함을 알 수 있다. 더불어, 사회적 위치, 나이 같은 개개인의 특징들을 Title안에서 더 뽑아낼 수 있을지도 모른다.
#### Rare Title 섹션을 만들어서 하나의 카테고리 안에 넣다보니, Sex에 관한 정보들을 잃는 현상을 발견하였다. 이를 위하여 "Rare Male", "Rare Female" 카테고리를 생성하려한다. (Rare 개수가 적어서 의미가 별로 없긴 하다.)
#### Title VS Sex 을 통하여 최종 결정트리의 첫번째 특성은 Title이며, Sex은 이러한 첫 분류 이후에는 쓰임이 없을 것이다.
"""
"""
# 지니 계수
#### *결정 트리*를 다루기 이전에, 이것이 어떻게 작동되는지 간단하게 알아보자. 알고리즘 자체의 목표는 항상 트리의 각 노드에 가장 최선의 분리(split)를 찾는 것이다. 하지만 주어진 split의 "성능"을 측정할 때 split를 결정짓는데 다양한 지표가 사용될 것이다. 대개 쓰이는 지표는 [Information Gain](https://en.wikipedia.org/wiki/Information_gain_in_decision_trees)(정보 획득).우리가 이용하는 것은 sklearn 라이브러리의 [Gini Impurity](https://en.wikipedia.org/wiki/Decision_tree_learning#Gini_impurity)지니계수이다.
#### 지니 계수는 한 집합의 요소들의 무질서함(disorder)을 측정한다.요소가 세트의 모든 클래스의 분포에 따라 무작위로 레이블링된다고 가정 할 때 요소가 잘못된 레이블이 될 확률을 계산한다. *결정 트리는 두개의 결과 노드 사이에 지니 계수를 줄이는 split를 찾는다.*

"""
#지니계수 계산 함수 정의하기
def get_gini_impurity(survived_count, total_count):
    survival_prob = survived_count/total_count #현재 survived 계산 값(survived 자체가 0,1로 되어있어서 두개의 범주 사이에 생각한다.)
    not_survival_prob = (1- survival_prob)
    
    random_observation_survived_prob = survival_prob
    random_observation_not_survived_prob = (1 - random_observation_survived_prob)
    
    mislabelling_survided_prob = not_survival_prob * random_observation_survived_prob #survived에 속하였을 때의 I값
    mislabelling_not_survided_prob = survival_prob * random_observation_not_survived_prob#not survived에 속하였을 때의 I값
    
    gini_impurity = mislabelling_survided_prob + mislabelling_not_survided_prob #합계
    
    return gini_impurity
"""
#### Sex와 Title 특징을 **예시로(위 특성 확인용으로만!)** 지니 계수를 얼마나 감소할 수 있는지 알아보자. 먼저 gini impurity를 계산하기 위해서는 시작 노드에 있는 초기 891개의 데이터를 이용해야 한다. 이를 통해 위 함수에 적용해보자.

#### + 밑에 처음 계산되는 지니계수 값은 초기 즉, 분리전 지니계수값을 의미한다.
"""
gini_impurity_starting_node = get_gini_impurity(342,891)
gini_impurity_starting_node
"""
#### 위의 값을 통해서 분리 전 값은 위와 같음을 알수 있다. 분리 후의 값을 특성 Sex와 Title을 각각 기준으로 계산해보자. 여기서 각각 특성의 경우를 위에를 참고하면 : 
- Sex : 남자 577명중 109명 생존, 여자 314명 중 233명 생존
- Title :  Mr 517명 중 81명 생존, 그 외 374명 중 261명 생존
"""
# 분리 후 Sex 특성에서의 각각의 지니계수 값을 본다면
gini_impurity_men = get_gini_impurity(109, 577)
print(gini_impurity_men)

gini_impurity_women = get_gini_impurity(233, 314)
print(gini_impurity_women)
# 분리 후 Title 특성에서의 각각의 지니계수 값을 본다면
gini_impurity_title_Mr = get_gini_impurity(81, 517)
print(gini_impurity_title_Mr)

gini_impurity_title_others = get_gini_impurity(261, 374)
print(gini_impurity_title_others)
# Sex의 분리 후 전체 지니계수값을 본다면
men_weight = 577/891
women_weight = 314/891
weighted_gini_impurity_sex_split = (gini_impurity_men * men_weight) + (gini_impurity_women * women_weight)
print(weighted_gini_impurity_sex_split)

#Title의 분리 후 전체 지니계수값을 본다면
title_1_weight = 517/891
title_others_weight = 374/891
weighted_gini_impurity_title_split = (gini_impurity_title_Mr * title_1_weight) + (gini_impurity_title_others * title_others_weight)
print(weighted_gini_impurity_title_split)
# 지니 계수 변화를 Sex, Title에서 각각 본다면
sex_gini_decrease = weighted_gini_impurity_sex_split - gini_impurity_starting_node
print(sex_gini_decrease)

title_gini_decrease = weighted_gini_impurity_title_split - gini_impurity_starting_node
print(title_gini_decrease)

"""
#### 분리전, 분리 후 지니계수 변화를 보면 Title 특성이 살짝 더 좋은 것을 알 수 있다.
"""
"""
# 교차검증(Cross-Validation)을 통한 최선의 나무 깊이 찾기
#### 데이터를 둘러본 뒤에 우리는 우리의 결정 트리와 관련된 모든 것을 찾아내야한다. 많은 양의 데이터가 잘못된 일반화를 하는 경우가 있기에 이것이 모든 데이터 과학 프로젝트의 중요한 지점이다. 과적합(학습 데이터에 과도하게 적합된 모델)이 보통 이유라고 들 수 있다. 이와 더불어, 시간이나 높은 상관관계를 가지는 특징들이 모델이 진정한 가치 하나를 건지는데 방해를 하여, 너무 많은 데이터로 인해 의미있는 관계를 놓치는 경우가 발생하기도 한다.
#### 결정 트리의 경우에, '트리 깊이' 파라미터는 모델이 각 예측에 이용할 최대 특성의 개수를 결정한다. 이 파라미터를 결정짓는 가장 좋은 방법은 가능한 깊이들을 계속 반복하다가 교차 검증을 통한 방식으로 평가를 하여 최선의 값을 찾는 방법이다.
#### 교차검증(Cross Validation)은 데이터를 "폴더"개수로 나누는 모델 검증 기술이다. 분리된 각각의 데이터들은 학습(Train) 및 평가(validate(test 아님!)) 목적으로 서로 서로 다른 데이터를 사용하므로 모델을 매번 다른 데이터로 학습하고 평가할 수 있다. 이 때문에 모든 데이터로 학습과 평가를 가능하게 하여 일반화가 굉장히 잘 될 수 있다는 장점을 가진다. 하지만 각각의 데이터 세트들에 대한 방대한 계산량이 요구 된다는 단점이 있다.
### + 교차 검증 추가 설명
#### 교차 검증에 쓰이는 데이터 셋은 엄연히 Train set이다. 여기서 평가(validate)되는 데이터 셋은 Train set 안에서 정의된 Test 셋이라 말할 수 있다. 평가 데이터셋 외의 데이터 셋은 Train set안에 있는 validate set 제외 되는 나머지 셋이다. 더 자세한 설명은 [이 링크](https://towardsdatascience.com/why-and-how-to-cross-validate-a-model-d6424b45261f?gi=956f6c4cd2ee)를 참고해주세요!
"""
cv = KFold(n_splits = 10) #cross validation에서 데이터 셋을 10개의 폴더로 나누어 계산
accuracies = list() # 정확도를 적을 리스트 생성

max_attributes = len(list(test)) #가지고 있는 특성  = 만들수 있는 최대 split 개수
depth_range = range(1, max_attributes + 1)

# Cross validation을 통한 최선의 max depth 결정
for depth in depth_range:
    fold_accuracy = []
    tree_model = tree.DecisionTreeClassifier(max_depth = depth)  # sklearn의 결정트리제조 부름
    
    # 각각에서 어떻게 할지 결정
    for train_fold, valid_fold in cv.split(train):
        
        # 일단 추출 작업
        f_train = train.loc[train_fold] # 전체에서 해당 학습 데이터 추출
        f_valid = train.loc[valid_fold] # 전체에서 해당 평가할 데이터 추출

        # 추출된 학습데이터 학습
        model = tree_model.fit(X = f_train.drop(['Survived'], axis=1), y = f_train["Survived"]) 
        # 학습된 모델을 바탕으로 평가(valid)
        valid_acc = model.score(X = f_valid.drop(['Survived'], axis=1), y = f_valid["Survived"])
        # 정확도 기록하기
        fold_accuracy.append(valid_acc)

    avg = sum(fold_accuracy)/len(fold_accuracy)
    accuracies.append(avg)
    
# 결과 정리 및 print하기
df = pd.DataFrame({"Max Depth": depth_range, "Average Accuracy": accuracies})
df = df[["Max Depth", "Average Accuracy"]]
print(df.to_string(index=False))
"""
#### 위의 결과를 통해 max depth = 3일 때 가장 높은 정확도를 보임을 알 수 있으며, max depth가 더 높을 수록 과적합의 영향으로 낮은 결과를 보임을 알 수 있다. 이를 통해 우리는 최종 모델의 max depth는 3으로 결정하게 되었다!
"""
"""
# 최종 트리Final Tree 결정하기
"""
# train, test 정리
y_train = train['Survived']
x_train = train.drop(['Survived'], axis=1).values 
x_test = test.values

# 결정 트리 정의 및 학습
decision_tree = tree.DecisionTreeClassifier(max_depth = 3)
decision_tree.fit(x_train, y_train)

# 학습된 결정 트리 바탕으로 Test set 예측하기
y_pred = decision_tree.predict(x_test)
submission = pd.DataFrame({"PassengerId": PassengerId,"Survived": y_pred}) #pandas 라이브러리로 제출해야되는 것들만 뽑아내기
submission.to_csv('submission.csv', index=False) #csv 형식 전환하기

print(submission.head(4))
"""
#### 이를 통하여 전체 학습과 예측은 끝이났습니다. 이에 더해 결정 트리 시각화하는 함수를 더하였습니다.
"""
# dot형식의 결정 트리 모델 확인해보기
with open("tree1.dot", 'w') as f:  #sklearn의 tree.export_graphviz 이용
     f = tree.export_graphviz(decision_tree,  
                              out_file=f, #파일 형식 정의
                              max_depth = 3,
                              impurity = True,
                              feature_names = list(train.drop(['Survived'], axis=1)),
                              class_names = ['Died', 'Survived'],
                              #이미지 형식 소개
                              rounded = True,
                              filled= True )
        
#.dot을 .png로 변환
check_call(['dot','-Tpng','tree1.dot','-o','tree1.png'])


img = Image.open("tree1.png")
draw = ImageDraw.Draw(img)
font = ImageFont.truetype('/usr/share/fonts/truetype/liberation/LiberationSerif-Bold.ttf', 26)
draw.text((10, 0), # Drawing offset (position)
          '"Title <= 1.5" corresponds to "Mr." title', # Text to draw
          (0,0,255), # RGB desired color
          font=font) # ImageFont object with desired font
img.save('sample-out.png')
PImage("sample-out.png")
# train set에서의 정확도 측정
acc_decision_tree = round(decision_tree.score(x_train, y_train) * 100, 2)
acc_decision_tree
"""
#### 드디어 결정 트리를 완성하였습니다! 이것은 82.38%의 정확도를 가지네요. 어떻게 그래프를 읽는지 살펴보겠습니다.
#### 각각의 노드의 첫번째 줄은 형식 "특성 <= 수치"을 가지며 분리 조건을 의미합니다. "Samples"는 단순히 이 노드에 포함된 데이터 개수를 의미합니다. "value"는 이 데이터셋 자체에서의 분포(생존, 미생존)을 나타냅니다. 마지막으로"class"는 각 노드의 상황/최종 상태를 의미합니다.(색깔로도 구분이 가능하다는 것을 볼 수 있습니다.)
#### 이 모델은 4가지 간단한 규칙으로 정의됨을 알 수 있습니다.
- "Mr" 타이틀을 가지고 있으면 살아남지 않음으로 분류(왼쪽 노드로)
- "Mr" 타이틀을 가지고 있지 않고, 가족 크기가 4명이하면 살아남음으로 분류
- "Mr" 타이틀을 가지고 있지 않고, 가족 크기가 4명 초과이고 Pclass가 2 이하면 살아남음으로 분류
- "Mr" 타이틀을 가지고 있지 않고, 가족 크기가 4명 초과이고 Pclass가 2 초과면 살아남음으로 분류

#### 읽어주셔서 감사합니다, Diego

#### + 잘못된 번역, 오역은 댓글로 남겨주시면 감사하겠습니다! 좋은 하루 보내세요:)
"""