"""
# 제4회 KISTI 캐글 대회
- https://www.kaggle.com/c/kisti-kaggle-competition-4th
- https://www.kaggle.com/t/bbe57dd38841427bacc18a5cf3683b59

"""
"""
## 사전 준비
### 1. 캐글 가입
- www.kaggle.com


"""
"""
## 2. KISTI 캐글 대회 참가 등록
- private 대회(in class)로 아래 링크를 이용하여 대회 참가 (Rules 승인)
    - https://www.kaggle.com/t/bbe57dd38841427bacc18a5cf3683b59
    


"""
"""
## 3. 데이터 다운로드 및 구글 드라이브에 올리기
### 1) 3 개의 파일 다운로드
- 훈련용 데이터: train.csv
- 테스트 데이터: test.csv
- 결과파일 샘플: sample_submission.csv

- www.kaggle.com 노트북을 사용하는 경우 /kaggle/input/ 디렉토리에 해당 파일들이 있음

### 2) 구글 드라이브 위치
- My Drive / KISTI / kaggle / datasets
"""
"""
### 4. titanic_4th_baseline.ipynb colab 실행
- 구글 드라이브 마운트
- 작업 디렉토리 설정
"""
"""
## BASELINE 테스트
### 1) ALL_1_submission.csv 파일 만들기 & Rank 확인
### 2) ALL_0.submission.csv 파일 만들기 & Rank 확인
### 3) baseline_submission.csv 파일 만들기 & Rank 확인

"""
"""
#### 셀마다 자동으로 소요 시간 출력
"""
!pip install ipython-autotime
%load_ext autotime
# 현재 작업 위치
!pwd
!ls -al
!ls -al /kaggle/input/kisti-kaggle-competition-4th
# 구글 드라이브 마운트
#from google.colab import drive
#drive.mount('gdrive')
#!ls -al ./gdrive

## 작업 디렉토리로 이동
#%cd "/content/gdrive/My Drive/KISTI/kaggle"
## 데이터셋 확인 
#!ls -al ./datasets
!pip install missingno
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# seaborn scheme 설정
plt.style.use('seaborn')
# 그래프의 폰트 설정
sns.set(font_scale=2.5) 
# 데이터셋의 missing data 쉽게 보여주기
import missingno as msno

#ignore warnings
#import warnings
#warnings.filterwarnings('ignore')

%matplotlib inline
"""
- [참고] matplotlib style
  - https://tonysyu.github.io/raw_content/matplotlib-style-gallery/gallery.html
"""
"""
### 작업 내용
- 1) 데이터셋 확인
  - null data 와 같은 데이터를 확인 및 수정
- 2) 탐색적 데이터 분석(Exploratory Data Analysis)
  - 여러 feature들을 개별적으로 분석
  - feature들 간의 상관 관계 확인
  - 여러 시각화 도구들을 사용
- 3) Feature Engineering
  - 모델을 만들기 전, 모델 성능을 높이기 위한 feature들을 engineering
  - one-hot encoding, class로 나누기, text 데이터 처리 등
- 4) Model 만들기
  - sklearn을 사용하여 모델 만들기
  - tensorflow, pytorch 등 딥러닝 프레임워크 사용도 가능
- 5) 모델 학습 및 예측
  - train set 을 가지고 모델 학습
  - test set을 사용하여 prediction
- 6) 모델 평가
  - 학습된 모델에 대한 예측 성능 평가
"""
"""
## 1. Dataset 확인
- 데이터를 테이블화하여 다루는 것이 편리
- pandas를 사용
  - 간단한 통계적 분석부터 복잡한 처리들을 간단한 메소드를 사용하여 처리

"""
#WORK_DIR = '/content'
#WORK_DIR = '.'
#df_train = pd.read_csv(WORK_DIR + '/datasets/train.csv')
#df_test = pd.read_csv(WORK_DIR + '/datasets/test.csv')

import os
# dataset 디렉토리 위치 
DATASET_DIR = "/kaggle/input/kisti-kaggle-competition-4th"

df_train = pd.read_csv(os.path.join(DATASET_DIR, "train.csv"))
df_test = pd.read_csv(os.path.join(DATASET_DIR, "test.csv"))

# 데이터 셋 살펴보기
df_train.head()
df_test.head()
"""
##### Features
- pclass : 클래스, Integer
- age : 나이, Integer
- sibsp : 형제와 배우자의 수, Integer
- parch : 부모와 아이의 수, Integer
- fare : 탑승료, Float
- survived : 생존여부, Integer (target label)

"""
# 통계적 수치 보기
df_train.describe()
df_test.describe()
"""
### NULL 데이터 체크
"""
# 학습 데이터 체크
for col in df_train.columns:
    print('column: {:>10}\t Percent of NULL value: {:.2f}%'.format(col, 
          100 * (df_train[col].isnull().sum() / df_train[col].shape[0])))

"""
- Age(약 20%), Cabin(약 80%), Embarked(약 0.2%)의 null data 존재 확인
"""
df_train.info()
# 테스트 데이터 체크
for col in df_test.columns:
    print('column: {:>10}\t Percent of NULL value: {:.2f}%'.format(col, 
          100 * (df_test[col].isnull().sum() / df_test[col].shape[0])))
df_test.info()
"""
##### MSNO 라이브러리를 사용하여 null data 확인
"""
# null data 분포 확인
msno.matrix(df=df_train.iloc[:, :], figsize=(8, 8), color=(0.8, 0.5, 0.2))
# null data 수로 확인
msno.bar(df=df_train.iloc[:, :], figsize=(8, 8), color=(0.8, 0.5, 0.2))
"""
### Target Label 확인
- target label 이 어떤 분포를 가지고 있는지 확인
- binary classification 같은 경우, 1과 0의 분포에 따라 모델 평가 방법이 달라질 수 있음
"""
df_train['Survived'].value_counts()
# 1행 2열 팔레트, 크기(세로:18, 가로:8)
f, ax = plt.subplots(1, 2, figsize=(18, 8))

# 파이 차트로 그리기
# value_counts() 의 data type은 series이며,
# series 타입은 plot을 가짐
# plt.plot(df_train['Survived'].value_counts()) 은 df_train[..]...plot()과 동일
df_train['Survived'].value_counts().plot.pie(explode=[0, 0.1], 
                           autopct='%1.1f%%', ax=ax[0], shadow=True)
ax[0].set_title('Pie plot - Survived')
ax[0].set_ylabel('')

sns.countplot('Survived', data=df_train, ax=ax[1])
ax[1].set_title('Count plot - Survived')

plt.show()
"""
- 38.4% 가 살아남음
- target label 의 분포가 어느 정도 균일(balanced)함

"""
"""
- [참고] plotly
"""
"""
## 2. Exploratory Data Analysis (EDA, 탐색적 데이터 분석)
"""
# 11개의 feature, 1개의 target label 
df_train.shape
"""
### Pclass (클래스)
- ordinal, 서수형 데이터, 카테고리형, 순서 있음
- pclass에 따른 생존률 차이 살펴보기
  - pandas의 group by 사용
"""
# Pclass 별 항목 갯수
df_train[['Pclass', 'Survived']].groupby(['Pclass'], as_index=True).count()
# Pclass별 생존자 수
# P1(136/216), P2(87/184), P3(119/491)
df_train[['Pclass', 'Survived']].groupby(['Pclass'], as_index=True).sum()
# crosstab 으로 확인
pd.crosstab(df_train['Pclass'], df_train['Survived'], 
            margins=True).style.background_gradient(cmap='summer_r')
# 클래스별 생존률
# P1 : (136 / (80+136)) => 63%
df_train[['Pclass', 'Survived']].groupby(['Pclass'], 
             as_index=True).mean().sort_values(by='Survived', 
                                   ascending=False).plot.bar()
"""
- Pclass가 좋을 수록 생존률이 높음
"""
# label에 따른 갯수 확인
y_position = 1.02
f, ax = plt.subplots(1, 2, figsize=(18, 8))
df_train['Pclass'].value_counts().plot.bar(
    color=['#CD7F32','#FFDF00','#D3D3D3'], ax=ax[0])
ax[0].set_title('Number of Passengers By Pclass', y=y_position)
ax[0].set_ylabel('Count')
sns.countplot('Pclass', hue='Survived', data=df_train, ax=ax[1])
ax[1].set_title('Pclass: Survived vs Dead', y=y_position)
plt.show()
"""
- 클래스가 높을 수록(1st class) 생존 확률이 높음
  - P1(63%), P2(48%), P3(25%)
- 생존에 Pclass가 큰 영향을 미친다고 생각할 수 있음
  - 모델을 만들 때, Pclass feature를 사용하는 것이 좋을 것이라 판단할 수 있음
"""
"""
### 성별(Sex)
- 성별로 생존률 확인
- pandas groupby와 seaborn countplot 사용

"""
f, ax = plt.subplots(1, 2, figsize=(18, 8))
df_train[['Sex', 'Survived']].groupby(['Sex'], 
                          as_index=True).mean().plot.bar(ax=ax[0])
ax[0].set_title('Survived vs Sex')
sns.countplot('Sex', hue='Survived', data=df_train, ax=ax[1])
ax[1].set_title('Sex: Survived vs Dead')
plt.show()
"""
- female(여성)이 생존할 확률이 높음
"""
df_train[['Sex', 'Survived']].groupby(['Sex'], 
            as_index=False).mean().sort_values(by='Survived', ascending=False)
# crosstab 으로 확인
pd.crosstab(df_train['Sex'], df_train['Survived'], 
            margins=True).style.background_gradient(cmap='summer_r')
"""
- Pclass와 마찬가지로, Sex도 예측 모델에 중요한 feature 임을 알 수 있음
"""
"""
### Pclass 와 Sex
- Pclass와 Sex 두 feature에 대한 생존 확률 확인
"""
# 3개의 차원 데이터로 이루어진 그래프 그리기
sns.factorplot('Pclass', 'Survived', hue='Sex', data=df_train, 
               size=6, aspect=1.5)
"""
- 모든 클래스에서 female이 생존할 확률이 male 보다 높음
- 남, 여 상관없이 클래스가 높을 수록 생존 확률이 높음
"""
# cloumn 대신 hue 사용
sns.factorplot(x='Sex', y='Survived', col='Pclass',
              data=df_train, satureation=.5,
               size=9, aspect=1)
sns.factorplot(x='Sex', y='Survived', hue='Pclass',
              data=df_train, satureation=.5,
               size=9, aspect=1)
"""
- [찾아보기] error bar
"""
"""
### Age
- 나이에 따른 생존 확률 확인
"""
# 간단한 통계 보기
print('제일 나이 많은 탑승객 : {:.1f} Years'.format(df_train['Age'].max()))
print('제일 어린 탑승객 : {:.1f} Years'.format(df_train['Age'].min()))
print('탑승객 평균 나이 : {:.1f} Years'.format(df_train['Age'].mean()))
# 생존에 따른 Age의 히스토그램
# kdeplot()
fig, ax = plt.subplots(1, 1, figsize=(9, 5))
sns.kdeplot(df_train[df_train['Survived'] == 1]['Age'], ax=ax)
sns.kdeplot(df_train[df_train['Survived'] == 0]['Age'], ax=ax)
plt.legend(['Survived == 1', 'Survived == 0'])
plt.show()
"""
- 나이가 어릴 수록 생존률이 높음
"""
# 히스토그램 vs. kdeplot()
# kdeplot()이 부드럽게 그림
# (참고) 커널밀도추정 https://blog.naver.com/loiu870422/220660847923
df_train[df_train['Survived']==1]['Age'].hist()
# pandas indexing
df_train.iloc[0,:]
for row in df_train.iterrows():
  break
row
df_train['Survived'] == 1
df_train[df_train['Survived']==1]
# Pclass와 Age 로 확인
plt.figure(figsize=(8, 6))
df_train['Age'][df_train['Pclass'] == 1].plot(kind='kde')
df_train['Age'][df_train['Pclass'] == 2].plot(kind='kde')
df_train['Age'][df_train['Pclass'] == 3].plot(kind='kde')

plt.xlabel('Age')
plt.title('Age Distribution within classes')
plt.legend(['1st Class', '2nd Class', '3rd Class'])
fig, ax = plt.subplots(1,3,figsize=(20,5))
sns.kdeplot(df_train[(df_train['Survived']==0) & (df_train['Pclass']==1)]['Age'], ax=ax[0])
sns.kdeplot(df_train[(df_train['Survived']==1) & (df_train['Pclass']==1)]['Age'], ax=ax[0])
ax[0].set_title('1st class')
ax[0].legend(['Survived==0', 'Survived==1'])   
sns.kdeplot(df_train[(df_train['Survived']==0) & (df_train['Pclass']==2)]['Age'], ax=ax[1])
sns.kdeplot(df_train[(df_train['Survived']==1) & (df_train['Pclass']==2)]['Age'], ax=ax[1])
ax[1].set_title('2nc class')
ax[1].legend(['Survived==0', 'Survived==1'])   
sns.kdeplot(df_train[(df_train['Survived']==0) & (df_train['Pclass']==3)]['Age'], ax=ax[2])
sns.kdeplot(df_train[(df_train['Survived']==1) & (df_train['Pclass']==3)]['Age'], ax=ax[2])
ax[2].set_title('3rd class')
ax[2].legend(['Survived==0', 'Survived==1'])                               
plt.show()

"""
- Class가 높을 수록 나이 많은 사람의 비중이 커짐
"""
# 나이 범위에 따른 생존률
cummulate_survival_ratio = []
for i in range(1, 80):
    cummulate_survival_ratio.append(
        df_train[df_train['Age'] < i]['Survived'].sum() / 
        len(df_train[df_train['Age'] < i]['Survived']))
    
plt.figure(figsize=(7, 7))
plt.plot(cummulate_survival_ratio)
plt.title('Survival rate change depending on range of Age', y=1.02)
plt.ylabel('Survival rate')
plt.xlabel('Range of Age(0~x)')
plt.show()
"""
- 나이가 어릴 수록 생존 확률이 높음
- Age는 중요한 feature 임을 알 수 있음
"""
"""
### Pclass, Sex, Age
- Pclass, Sex, Age 세 개의 feature에 대한 시각화
- seaborn violinplot 사용
  - x축 : 나누어 보고 싶은 case (Pclass, Sex)
  - y축 : 보고 싶은 distribution (Age)
"""
# scale='count', scale='area'
f,ax=plt.subplots(1,2,figsize=(18,8))
sns.violinplot("Pclass","Age", hue="Survived", data=df_train, scale='count', 
               split=True,ax=ax[0])
ax[0].set_title('Pclass and Age vs Survived')
ax[0].set_yticks(range(0,110,10))
sns.violinplot("Sex","Age", hue="Survived", data=df_train, scale='count', 
               split=True,ax=ax[1])
ax[1].set_title('Sex and Age vs Survived')
ax[1].set_yticks(range(0,110,10))
plt.show()
"""
- 왼쪽 그림: Pclass 별로 Age의 분포가 어떻게 다른지, 생존 여부에 따라 구분한 그래프
- 오른쪽 그림: Sex, Age에 따른 생존 여부
- 모든 클래스에서 나이가 어릴 수록 생존률이 높음
- 오른쪽 그림에서, female 이 생존률이 높음
- 여성과 아이를 먼저 챙긴 것을 알 수 있음
"""
"""
### Embarked
- 탑승한 항구에 따른 생존률 확인
"""
f, ax = plt.subplots(1, 1, figsize=(7, 7))
df_train[['Embarked', 'Survived']].groupby(['Embarked'], 
              as_index=True).mean().sort_values(by='Survived', 
                                      ascending=False).plot.bar(ax=ax)
"""
- 생존률이 비슷
"""
# 다른 feature로 split하여 확인
f,ax=plt.subplots(2, 2, figsize=(20,15))
sns.countplot('Embarked', data=df_train, ax=ax[0,0])
ax[0,0].set_title('(1) No. Of Passengers Boarded')
sns.countplot('Embarked', hue='Sex', data=df_train, ax=ax[0,1])
ax[0,1].set_title('(2) Male-Female Split for Embarked')
sns.countplot('Embarked', hue='Survived', data=df_train, ax=ax[1,0])
ax[1,0].set_title('(3) Embarked vs Survived')
sns.countplot('Embarked', hue='Pclass', data=df_train, ax=ax[1,1])
ax[1,1].set_title('(4) Embarked vs Pclass')
plt.subplots_adjust(wspace=0.2, hspace=0.5)
plt.show()
"""
- Figure 1: S에서 가장 많은 사람이 탑승
- Figure 2: C와 Q는 남녀 비율이 비슷, S는 남자가 더 많음
- Figure 3: S가 생존확률이 가장 낮음
- Figure 4: C가 생존 확률이 높음. 클래스가 높은 사람이 많이 탄 이유. S는 3rd class가 많아서 생존 확률이 낮음
"""
"""
### Family
- SibSp(형제 자매)
- Parch(부모, 자녀)
"""
# 새로운 컬럼(Family) 추가
# series 타입은 서로 더할 수 있음
# 자신을 포함하기 위해 1을 더함
df_train['FamilySize'] = df_train['SibSp'] + df_train['Parch'] + 1 
df_test['FamilySize'] = df_test['SibSp'] + df_test['Parch'] + 1 

print("Maximum size of Family: ", df_train['FamilySize'].max())
print("Minimum size of Family: ", df_train['FamilySize'].min())
# Family 크기와 생존 관계
f,ax=plt.subplots(1, 3, figsize=(40,10))
sns.countplot('FamilySize', data=df_train, ax=ax[0])
ax[0].set_title('(1) No. Of Passengers Boarded', y=1.02)

sns.countplot('FamilySize', hue='Survived', data=df_train, ax=ax[1])
ax[1].set_title('(2) Survived countplot depending on FamilySize',  y=1.02)

df_train[['FamilySize', 'Survived']].groupby(['FamilySize'], 
                    as_index=True).mean().sort_values(by='Survived', 
                                         ascending=False).plot.bar(ax=ax[2])
ax[2].set_title('(3) Survived rate depending on FamilySize',  y=1.02)

plt.subplots_adjust(wspace=0.2, hspace=0.5)
plt.show()
"""
- Figure 1: 가족 크기는 1 ~ 11. 대부분 1명, 그 다음은 2~4명
- Figure 2, 3: 
  - 가족이 4명인 경우 생존 확률이 가장 높음
  - 가족 수가 많아질 수록 생존 확률이 낮아짐
  - 가족 수가 너무 작거나, 너무 커도 생존 확률이 낮음
  - 가족 수 3~4명이 생존 확률이 높음
"""
"""
### Fare (탑승 요금)
- continuous feature

"""
# histogram
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
g = sns.distplot(df_train['Fare'], color='b', 
                 label='Skewness : {:.2f}'.format(df_train['Fare'].skew()), ax=ax)
g = g.legend(loc='best')
"""
- distribution이 비대칭 (high skewness)
  - 이대로 모델에 넣어 줄 경우, 모델이 잘못 학습할 수 있음
  - outlier에 민감하게 반응한다면 예측시에 좋지 못한 결과를 부름
- outlier의 영향을 줄이기 위해 Fare에 log 적용
- pandas DataFrame의 특정 컬럼에 공통된 작업(함수)을 적용하는 경우,  map 또는 apply 사용

"""
# NULL값 치환
df_train.loc[df_train.Fare.isnull(), 'Fare'] = df_train['Fare'].mean()
df_test.loc[df_test.Fare.isnull(), 'Fare'] = df_test['Fare'].mean()

df_train['Fare'] = df_train['Fare'].map(lambda i: np.log(i) if i>0 else 0)
df_test['Fare'] = df_test['Fare'].map(lambda i: np.log(i) if i>0 else 0)

fig, ax = plt.subplots(1, 1, figsize=(8, 8))
g = sns.distplot(df_train['Fare'], color='b', 
            label='Skewness : {:.2f}'.format(df_train['Fare'].skew()), ax=ax)
g = g.legend(loc='best')
"""
- log를 취하니, 비대칭성이 많이 사라짐
- feature engineering 적용
- 모델을 학습시키고, 모델의 성능을 높이기 위해 feature 들에 여러 조작을 가하거나, 새로운 feature를 추가하는 작업
"""
"""
### Cabin
- NaN 이 약 80%
- 생존에 영향을 미칠 중요한 정보를 얻어내기는 쉽지 않음
- 모델에 포함하지 않는 것이 좋음
"""
df_train.head()
"""
### Ticket
- 다양한 문자열이 많음
- 모델에 적용하기 위해서 다양한 아이디어 필요
"""
df_train['Ticket'].value_counts()

"""
- ticket number 가 매우 다양함
- 일단, 제외
- [참고] 참고한 사이트
  - https://www.kaggle.com/arthurtok/introduction-to-ensembling-stacking-in-python, https://www.kaggle.com/startupsci/titanic-data-science-solutions, https://www.kaggle.com/ash316/eda-to-prediction-dietanic, https://www.kaggle.com/yassineghouzam/titanic-top-4-with-ensemble-modeling 
"""
"""
## 3. Feature Engineering
- dataset에 존재하는 null data 채우기
- null data를 포함하는 feature의 statistics를 참고하거나, 다른 아이디어 필요
- 모델의 성능에 영향을 주는 중요한 작업
- train 뿐만 아니라 test dataset에도 동일하게 적용해야 함
"""
"""
### Age의 NULL 처리
- Age에는 null 데이터가 177개나 존재
- title과 statistics를 사용하여 채워보기
  - Miss, Mrr, Mrs 사용
- pandas의 str.extract()를 사용하여 title 추출 (정규표현식 사용)
"""
df_train['Age'].isnull().sum()
df_train['Name']
df_train['Name'].str.extract('([A-Za-z]+)\.')
# initial 항목으로 추출
df_train['Initial']=0
for i in df_train:
    df_train['Initial']= df_train.Name.str.extract('([A-Za-z]+)\.') 
    
df_test['Initial']=0
for i in df_test:
    df_test['Initial']= df_test.Name.str.extract('([A-Za-z]+)\.')
# Sex와 Initial에 대한 crosstab 확인
pd.crosstab(df_train['Initial'], df_train['Sex']).T.style.background_gradient(cmap='summer_r')
# 위 테이블을 참고하여,
# initial 치환
df_train['Initial'].replace(['Mlle','Mme','Ms','Dr','Major','Lady','Countess',
                          'Jonkheer','Col','Rev','Capt','Sir','Don', 'Dona'],
                        ['Miss','Miss','Miss','Mr','Mr','Mrs','Mrs','Other',
                       'Other','Other','Mr','Mr','Mr', 'Mr'],inplace=True)

df_test['Initial'].replace(['Mlle','Mme','Ms','Dr','Major','Lady','Countess',
                          'Jonkheer','Col','Rev','Capt','Sir','Don', 'Dona'],
                        ['Miss','Miss','Miss','Mr','Mr','Mrs','Mrs','Other',
                         'Other','Other','Mr','Mr','Mr', 'Mr'],inplace=True)
pd.crosstab(df_train['Initial'], df_train['Sex']).T.style.background_gradient(cmap='summer_r')
df_train.groupby('Initial').mean()
# 생존률 확인
df_train.groupby('Initial')['Survived'].mean().plot.bar()
"""
- 어린 아이(Master)와 여성과 관계 있는 Miss, Mrs가 생존률이 높음
"""
"""
#### train, test 전체 셋을 사용하여 Age의 null 값 처리
- pandas의 concat을 이용하여 dataframe을 합침

"""
df_all = pd.concat([df_train, df_test])
df_all
df_all.reset_index(drop=True)
df_all.groupby('Initial').mean()
"""
- Age의 평균을 이용하여 Null 값 채우기
  - Mr인 경우, Age 값을 33으로 치환
- loc + boolean + column을 사용하여 값을 치환하는 방법
- [참고] 다른 방법 참고:
  - https://www.kaggle.com/yassineghouzam/titanic-top-4-with-ensemble-modeling
"""
df_train.loc[(df_train.Age.isnull())&(df_train.Initial=='Mr'),'Age']=33
df_train.loc[(df_train.Age.isnull())&(df_train.Initial=='Mrs'),'Age']=37
df_train.loc[(df_train.Age.isnull())&(df_train.Initial=='Master'),'Age']=5
df_train.loc[(df_train.Age.isnull())&(df_train.Initial=='Miss'),'Age']=22
df_train.loc[(df_train.Age.isnull())&(df_train.Initial=='Other'),'Age']=45

df_test.loc[(df_test.Age.isnull())&(df_test.Initial=='Mr'),'Age']=33
df_test.loc[(df_test.Age.isnull())&(df_test.Initial=='Mrs'),'Age']=37
df_test.loc[(df_test.Age.isnull())&(df_test.Initial=='Master'),'Age']=5
df_test.loc[(df_test.Age.isnull())&(df_test.Initial=='Miss'),'Age']=22
df_test.loc[(df_test.Age.isnull())&(df_test.Initial=='Other'),'Age']=45
df_train['Age'].isnull().sum()
df_test['Age'].isnull().sum()
"""
#### Embarked의 Null 값 처리
- null 값이 2개 있으며, S에서 탑승객이 가장 많음므로 null을 S로 채움
- dataframe의 fillna() 사용
"""
df_train['Embarked'].isnull().sum()
df_train.shape
df_train['Embarked'].fillna('S', inplace=True)
"""
### Age 변환
- continus 값을 categorical 값으로 변환
  - 정보 손실이 있을 수 있으므로 주의가 필요
- Age를 몇 개의 group으로 나누어서 category화 시킴
- dataframe의 loc 또는 apply() 사용
"""
df_train['Age_cat'] = 0

df_train.head()
# loc 이용
# 10살 간격으로 나누기
df_train['Age_cat'] = 0
df_train.loc[df_train['Age'] < 10, 'Age_cat'] = 0
df_train.loc[(10 <= df_train['Age']) & (df_train['Age'] < 20), 'Age_cat'] = 1
df_train.loc[(20 <= df_train['Age']) & (df_train['Age'] < 30), 'Age_cat'] = 2
df_train.loc[(30 <= df_train['Age']) & (df_train['Age'] < 40), 'Age_cat'] = 3
df_train.loc[(40 <= df_train['Age']) & (df_train['Age'] < 50), 'Age_cat'] = 4
df_train.loc[(50 <= df_train['Age']) & (df_train['Age'] < 60), 'Age_cat'] = 5
df_train.loc[(60 <= df_train['Age']) & (df_train['Age'] < 70), 'Age_cat'] = 6
df_train.loc[70 <= df_train['Age'], 'Age_cat'] = 7

df_test['Age_cat'] = 0
df_test.loc[df_test['Age'] < 10, 'Age_cat'] = 0
df_test.loc[(10 <= df_test['Age']) & (df_test['Age'] < 20), 'Age_cat'] = 1
df_test.loc[(20 <= df_test['Age']) & (df_test['Age'] < 30), 'Age_cat'] = 2
df_test.loc[(30 <= df_test['Age']) & (df_test['Age'] < 40), 'Age_cat'] = 3
df_test.loc[(40 <= df_test['Age']) & (df_test['Age'] < 50), 'Age_cat'] = 4
df_test.loc[(50 <= df_test['Age']) & (df_test['Age'] < 60), 'Age_cat'] = 5
df_test.loc[(60 <= df_test['Age']) & (df_test['Age'] < 70), 'Age_cat'] = 6
df_test.loc[70 <= df_test['Age'], 'Age_cat'] = 7
df_train.head()
# apply() 함수 사용한 방법
def category_age(x):
    if x < 10:
        return 0
    elif x < 20:
        return 1
    elif x < 30:
        return 2
    elif x < 40:
        return 3
    elif x < 50:
        return 4
    elif x < 60:
        return 5
    elif x < 70:
        return 6
    else:
        return 7    
    
df_train['Age_cat_2'] = df_train['Age'].apply(category_age)

df_train.head()
# 두 가지 방법의 비교
# all() : 모두 True 일 때, True
# any() : 하나라도 True이면 True
(df_train['Age_cat'] == df_train['Age_cat_2']).all()
# Age 컬럼 삭제
# axis=1
df_train.drop(['Age', 'Age_cat_2'], axis=1, inplace=True)
df_test.drop(['Age'], axis=1, inplace=True)
"""
### Initial 변경
- Mr, Mrs, Miss, Master, Other 로 구성
- 카테고리로 표현되어져 있는 데이터를 컴퓨터가 인식할 수 있도록 수치화
- map() 사용
"""
df_train.Initial.unique()
df_train['Initial'] = df_train['Initial'].map(
    {'Master': 0, 'Miss': 1, 'Mr': 2, 'Mrs': 3, 'Other': 4})
df_test['Initial'] = df_test['Initial'].map(
    {'Master': 0, 'Miss': 1, 'Mr': 2, 'Mrs': 3, 'Other': 4})
df_train.Initial.unique() 
df_train.Initial.unique()
"""
### Embarked 변경
- S, C, Q로 구성
"""
df_train['Embarked'].unique()
df_train['Embarked'].value_counts()
df_train['Embarked'] = df_train['Embarked'].map({'C': 0, 'Q': 1, 'S': 2})
df_test['Embarked'] = df_test['Embarked'].map({'C': 0, 'Q': 1, 'S': 2})
df_train.head()
# null 확인
df_train['Embarked'].isnull().any()
"""
### Sex 변경
- male, female 로 구성
"""
df_train['Sex'].unique()
df_train['Sex'] = df_train['Sex'].map({'female': 0, 'male': 1})
df_test['Sex'] = df_test['Sex'].map({'female': 0, 'male': 1})
df_train['Sex'].unique()
"""
#### Pearson Correlation
- feature 들 간의 상관 관계 알아보기
- (-1, 1) 사이의 값
  - -1로 갈수록 음의 상관 관계
  - 1로 갈수록 양의 상관 관계
  - 0 : 상관 관계가 없음
- matrix 형태의 heatmap plot 사용
"""
heatmap_data = df_train[['Survived', 'Pclass', 'Sex', 'Fare', 
                         'Embarked', 'FamilySize', 'Initial', 'Age_cat']] 

colormap = plt.cm.RdBu
plt.figure(figsize=(14, 12))
plt.title('Pearson Correlation of Features', y=1.05, size=15)
sns.heatmap(heatmap_data.astype(float).corr(), linewidths=0.1, vmax=1.0,
           square=True, cmap=colormap, linecolor='white', annot=True, 
            annot_kws={"size": 16})

del heatmap_data
"""
- Sex, Pclass와 Survived에 상관 관계가 어느 정도 있음
- Pclass와 Age_cat, Age_cat과 Initial 은 상관 관계 있음
- 서로 강한 상관 관계를 가지는 feature들은 없음
  - 모델을 학습시킬 때, 불필요한 feature는 없음을 의미 (redundant, superfluous feature 들)
  
"""
"""
## One-hot encoding
- 카테고리 데이터를 (0, 1)로 이루어진 N차원 벡터로 나타내는 것
- pandas.get_dummies() 사용
"""
"""
### Initial 을 One-hot encoding으로 만들기
"""
df_train = pd.get_dummies(df_train, columns=['Initial'], prefix='Initial')
df_test = pd.get_dummies(df_test, columns=['Initial'], prefix='Initial')

df_train.head()
"""
### Embarked를 one-hot encoding


"""
df_train = pd.get_dummies(df_train, columns=['Embarked'], prefix='Embarked')
df_test = pd.get_dummies(df_test, columns=['Embarked'], prefix='Embarked')
df_train.head()
"""
## Drop columns 
- 불필요한 컬럼들 지우기

"""
df_train.drop(['PassengerId', 'Name', 'SibSp', 'Parch', 'Ticket', 'Cabin'], axis=1, inplace=True)
df_test.drop(['PassengerId', 'Name',  'SibSp', 'Parch', 'Ticket', 'Cabin'], axis=1, inplace=True)

df_train.head()
df_test.head()
"""
## 4. 모델 만들기
- sklearn 사용
  - feature engineering, preprocessing, 지도 학습 알고리즘, 비지도 학습 알고리즘, 모델 평가, 파이프 라인 등 구현
- titanic 문제
  - target class : Survived
    - 0, 1 로 이루어진 binary classification 문제
  - train set의 Survived 항목을 제외한 입력을 가지고, 모델을 최적화시켜서 각 샘플(탑승객)의 생존 유무를 판단하는 모델 만들기
  - 모델이 학습하지 않은 test set을 입력으로 주어서 test set의 각 샘플(탑승객)의 생존 유무 예측
"""
from sklearn.ensemble import RandomForestClassifier  
from sklearn import metrics 
from sklearn.model_selection import train_test_split
"""
### 준비 - 데이터 셋을 train, valid, test set으로 나누기
- 보통은 train, test set으로 나누지만, valid set으로 모델 평가
  - train : 팀 훈련
  - valid : 평가전
  - test : 대회
"""
# 학습에 쓰일 데이터와 target label 분리
X_train = df_train.drop('Survived', axis=1).values
target_label = df_train['Survived'].values
X_test = df_test.values
X_tr, X_vld, y_tr, y_vld = train_test_split(X_train, target_label, test_size=0.3, random_state=2018)
"""
- [참고] 머신러닝 알고리즘
  - http://scikit-learn.org/stable/supervised_learning.html#supervised-learning
"""
"""
- 랜덤 포레스트 모델
  - 결정 트리 기반 모델
  - 여러 결정 트리들을 앙상블한 모델
  - 파라미터
    - n_estimators, max_features, max_depth, min_samples_split, min_samples_leaf
  - 파라미터 튜닝에 따라 모델 성능이 달라짐
  
"""
"""
### 모델 생성 및 예측
- RandomForestClassifier()
- fit()
- predict()
"""
# 학습
model = RandomForestClassifier()
model.fit(X_tr, y_tr)

# 예측
prediction = model.predict(X_vld)
prediction
# 정확도
print('총 {}명 중 {:.2f}% 정확도로 생존을 맞춤'.format(y_vld.shape[0], 100 * metrics.accuracy_score(prediction, y_vld)))
print(X_tr.shape)
print(X_vld.shape)
(prediction == y_vld).sum()/prediction.shape[0]
"""
### Feature Importance
- 학습된 모델은 feature importance를 가짐
- 만든 모델이 어떤 feature에 영향을 많이 받는지 확인할 수 있음
- pandas series 사용
"""
model.feature_importances_
df_train.head()

from pandas import Series
feature_importance = model.feature_importances_
Series_feat_imp = Series(feature_importance, index=df_test.columns)
plt.figure(figsize=(8, 8))
Series_feat_imp.sort_values(ascending=True).plot.barh()
plt.xlabel('Feature importance')
plt.ylabel('Feature')
plt.show()
"""
- Fare가 가장 큰 영향력을 가짐. 그 뒤에 Initial_2, Age_cat, Pclass 순으로 중요도를 가짐
- Fare가 중요한 feature일 수 있다고 판단을 내릴 수도 있지만, 결국 모델에 귀속되는 하나의 결론임. 통계적으로 더 살펴봐야 함
- 좀 더 정확도 높은 모델을 얻기 위해 feature selection을 할 수도 있고, 좀 더 빠른 모델을 만들기 위해서는 feature를 제가할 수도 있음
"""
"""
### Test Set을 사용하여 Prediction
- 모델을 학습하지 않았던 테스트 셋으로 생존 여부 예측
- 캐글에서 준 파일 gender_submission.csv 을 사용하여 제출 준비

"""
#WORK_DIR = '/content'
#WORK_DIR = '.'
#submission = pd.read_csv(WORK_DIR + '/datasets/sample_submission.csv')

submission = pd.read_csv(os.path.join(DATASET_DIR, 'sample_submission.csv'))

submission.head()
"""
#### test set에 대하여 예측하고, 결과를 csv에 저장
"""
prediction = model.predict(X_test)
submission['Survived'] = prediction

submission.to_csv('./kisti_kaggle_baseline_submission.csv', index=False)
!head -10 ./kisti_kaggle_baseline_submission.csv
!ls -al
"""
### 캐글에 제출하기
- 1) 명령어로 제출
    - Commit
    - OUTPUT
    - Submit to Competition
- 2) 웹 페이지에서 제출
    - kaggle.com 접속
    - Submit Predictions 클릭하여 업로드
- 3) 캐글 사이트 노트북으로 실행하는 경우 (Save Version)을 통해 제출할 수 있음
    - Save Version => Save & Run all(commit)



"""
#!kaggle competitions submit -c titanic -f baseline_submission.csv -m baseline_submit
#from google.colab import files
#files.download("baseline_submission.csv")

"""
# NEXT...
- Feature Engineering
  - Fare에 log() 적용했던 부분을 취소하고 commit 수행
    - 결과는 더 안 좋아짐 확인!
- 다양한 알고리즘 적용
    - Light GBM
    - CatBoost
    - :
  
"""
"""
- [참고]
  - https://www.kaggle.com/arthurtok/introduction-to-ensembling-stacking-in-python, https://www.kaggle.com/startupsci/titanic-data-science-solutions, https://www.kaggle.com/ash316/eda-to-prediction-dietanic, https://www.kaggle.com/yassineghouzam/titanic-top-4-with-ensemble-modeling 
"""