(필사커널) 190717 EDA To Prediction(DieTanic)
In [1]:
from IPython.core.display import display, HTML
display(HTML("<style> .container{width:90% !important;}</style>"))

경진대회 : Titanic: Machine Learning from Disaster
https://www.kaggle.com/c/titanic

원본 커널 : EDA To Prediction(DieTanic)
https://www.kaggle.com/ash316/eda-to-prediction-dietanic

Contents of the Notebook

Part 1. EDA:

(1) Feature 분석

(2) 여러 Feature들간의 관계나 트렌드 찾기

Part 2. Feature Engineering and Data Cleansing:

(1) 새로운 Feature 더하기

(2) Redundant한 Feature 제거

(3) Feature를 모델링에 적합한 형태로 변환하기

Part 3. Predictive Modeling

(1) 기본 알고리즘 수행

(2) Cross Validation

(3) Ensembling

(4) 중요한 Feature 추출

Part 1. Exploratory Data Analysis(EDA):

In [2]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('fivethirtyeight')
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
In [3]:
data = pd.read_csv('input/train.csv')
In [4]:
data.head()
Out[4]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
In [5]:
data.isnull().sum() # 전체 Null 값 확인
Out[5]:
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64

Age, Cabin, Embarked 에 Null 값이 있습니다. 나중에 이것들을 수정해보겠습니다.

얼마나 생존을 했을까??

In [6]:
f, ax = plt.subplots(1, 2, figsize=(15, 6))

data['Survived'].value_counts().plot.pie(explode = [0,0.1], autopct = '%1.1f%%', ax=ax[0], shadow=True)
ax[0].set_title('Survived')
ax[0].set_ylabel(' ')

sns.countplot('Survived', data=data, ax=ax[1])
ax[1].set_title('Survived')

plt.show()

많은 탑승객들이 생존하지 못했습니다.

Training Set의 891명 탑승객 중 약 350명(38.4%)만이 이 사고로부터 생존했습니다.

데이터로부터 다른 인사이트를 얻고 어떤 유형의 탑승객이 생존했고, 그렇지 못했는지 살펴보기 위해 더 들어가보갰습니다.

데이터셋의 여러 feature들을 사용해서 생존률을 체크해보겠습니다.

다룰 feature들은 Sex(성별), Port of Embarkation(탑승항구), Age(연령) 등 입니다.

먼저 feature들의 유형에 대해 이해해보겠습니다.

Feature의 유형

  • Categorical Features: (카테고리형 Feature)

    카테고리형 변수(Categorical Variable)은 그 값으로 두개 이상의 카테고리를 가지고 각각의 값으로 feature가 카테고리화 될 수 있습니다.
    예를 들어 성별은 두개의 카테고리(남성과 여성)를 가진 카테고리형 변수입니다. 이런 변수는 순서를 부여할 수가 없습니다.
    다른 말로 명목변수(Nomial Variable) 라고도 합니다.

- 데이터셋의 Categorical Feature : Sex, Embarked
  • Ordinal Features: (순서형 Feature)

    : 순서형 변수(Ordinal Variable)은 카테고리형 변수와 비슷하지만, 변수 안 각 값들간 상대적인 순서, 분류를 부여할 수 있다는 점이 다릅니다.
    가령, Tall, Medium, Short의 값을 가진 Height와 같은 feature는 순서형 변수입니다. 이 변수 안에서 우리가 상대적인 분류가 가능하기 때문입니다.

- 데이터셋의 Ordinal Feature : Pclass
  • Continuous Features: (연속형 Feature)

    : 어떤 변수가 특정 두 지점, 혹은 최댓값과 최솟값 사이에 어떤 값이든 가질 수 있다면 그 변수는 연속형입니다.

 - 데이터셋의 Continuous Feature : Age

Feature 분석하기

Sex → Categorical Feature

In [7]:
data.groupby(['Sex','Survived'])['Survived'].count().to_frame()
Out[7]:
Survived
Sex Survived
female 0 81
1 233
male 0 468
1 109
In [8]:
f, ax = plt.subplots(1, 2, figsize=(15,6))

data[['Sex', 'Survived']].groupby(['Sex']).mean().plot.bar(ax=ax[0])
ax[0].set_title('Survived vs Sex')

sns.countplot('Sex', hue='Survived', data=data, ax=ax[1])
ax[1].set_title('Sex : Survived vs Dead')

plt.show()

흥미로운 결과 입니다. 남자 탑승객의 수가 여자 탑승객의 수보다 훨씬 많습니다.
그렇지만 여자 생존 탑승객의 수가 남자 생존 탑승객의 수보다 거의 두배 많습니다.
여성의 생존률은 약 75% 정도인데 반해 남자의 생존률은 18~19% 정도입니다.

때문에 성별은 모델링에 매우 중요한 feature일 것입니다.
하지만 이것이 최선일지 다른 feature들을 살펴보겠습니다.

Pclass --> Ordinal Feature

In [9]:
pd.crosstab(data.Pclass, data.Survived, margins = True).style.background_gradient(cmap='summer_r')
Out[9]:
Survived 0 1 All
Pclass
1 80 136 216
2 97 87 184
3 372 119 491
All 549 342 891
In [10]:
f, ax = plt.subplots(1, 2, figsize= (15,6))

data['Pclass'].value_counts().plot.bar(color=['#CD7F32', '#FFDF00', '#D3D3DE'], ax=ax[0])
ax[0].set_title('Number of Passengers by Pcass')
ax[0].set_ylabel('')

sns.countplot('Pclass', hue='Survived', data=data, ax=ax[1])
ax[1].set_title('Plcass : Survived vs Dead.')
Out[10]:
Text(0.5, 1.0, 'Plcass : Survived vs Dead.')

돈으로 모든것을 살 수 없다고 흔히들 말하지만 Pclass 1 의 생존자가 구조 시에 매우 우선 순위에 있었던 것 같습니다.
Pclass 3의 탑승객 수가 훨씬 많았지만, 생존자 비율은 25% 정도로 매우 낮습니다.

Pclass 1의 생존률은 63%, Pclass 2의 생존률은 48% 정도입니다. 결국, 돈과 지위가 중요한 요소로 작용한 듯 합니다.

다른 흥미로운 점을 찾기 위해 더 들어가보겠습니다. 이번에는 Sex와 Pclass를 함께 두고 생존률을 체크해보겠습니다.

In [11]:
pd.crosstab([data.Sex, data.Survived], data.Pclass, margins = True).style.background_gradient(cmap='summer_r')
Out[11]:
Pclass 1 2 3 All
Sex Survived
female 0 3 6 72 81
1 91 70 72 233
male 0 77 91 300 468
1 45 17 47 109
All 216 184 491 891
In [12]:
sns.factorplot('Pclass', 'Survived', hue='Sex', data=data)

plt.show()

이번 케이스에서는 Categorical Value를 쉽게 보기 위해 Factor Plot을 사용했습니다.

CrossTab과 FactorPlot을 보면 Pclass 1 여성 탑승객의 생존률이 95~96% 가량으로 사망자는 3명 정도만 있습니다.

그리고 Pclass와 무관하게, 여성이 구조에 있어서 우선 순위에 있었습니다. 남성의 경우 Pclass 1라도 생존률은 매우 낮습니다.

Pclass 또한 중요한 feature 로 보입니다. 다른 feature를 또 분석해보겠습니다.

Age → Continuous Feature

In [13]:
print('Oldest Passenger was of: ', data['Age'].max(),'Years')
print('Youngest Passeger was of: ', data['Age'].min(),'Years')
print('Average Age on the ship: ', data['Age'].mean(), 'Years')
Oldest Passenger was of:  80.0 Years
Youngest Passeger was of:  0.42 Years
Average Age on the ship:  29.69911764705882 Years
In [14]:
f, ax = plt.subplots(1, 2, figsize = (15,6))

sns.violinplot('Pclass', 'Age', hue='Survived', data=data,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=data, split = True,  ax=ax[1])
ax[1].set_title('Sex and Age vs Survived')
ax[1].set_yticks(range(0,110,10))

plt.show()

관찰결과 :

1) Pclass 등급이 낮아짐(1 to 3)에 따라 어린이의 수는 증가하고, 10세 이하의 탑승객 수는 Pclass 수와 관계 없이 좋아보입니다.

2) 20-50세 사이의 Pclass 1 탑승객 생존률은 높고, 여성의 경우에는 더욱 높습니다.

3) 남성은 연령이 증가할수록 생존 확률이 줄어듭니다.

앞에서 본 것처럼, Age Feature는 177개의 Null 값을 가지고 있습니다.
이 값들을 데이터 셋의 평균 값으로 대체할 수 있습니다.

하지만 사람들의 연령은 많고 다양합니다. 우리는 자칫 4세 아이의 연령에게 평균 연령 29세를 부여할 수도 있습니다.
승객이 어떤 연령대에 속했는지 알 수 있는 방법이 없을까요?

우리는 이를 위해 Name Feature를 체크해볼 수 있습니다. Name을 보면 Mr와 Mrs 와 같은 salutation이 있습니다.
그렇기 때문에 Mr와 Mrs 의 평균 값을 각각의 그룹에 부여할 수 있습니다.

Name을 통해 Feature를 추출할 수 있습니다.

In [15]:
data['Initial'] = 0
data['Initial'] = data.Name.str.extract('([A-aZ-z]+)\.') # salutation을 추출합니다.

정규표현식 ( [A-Za-z]+). 를 사용했습니다. 이 정규표현식은 A-Z 또는 a-z 사이의 문자열과 그 뒤에 있는 .(dot)을 찾아냅니다.
이것으로 Name에서 Salutation을 추출했습니다.

In [16]:
pd.crosstab(data.Initial, data.Sex).T.style.background_gradient(cmap='summer_r') # 성별에 따른 Initial 체크
Out[16]:
Initial Capt Col Countess Don Dr Jonkheer Lady Major Master Miss Mlle Mme Mr Mrs Ms Rev Sir
Sex
female 0 0 1 0 1 0 1 0 0 182 2 1 0 125 1 0 0
male 1 2 0 1 6 1 0 2 40 0 0 0 517 0 0 6 1

Miss를 나타내는 Mlle, Mme와 같은 잘못 적힌 Initial 이 있습니다. 이 값들을 Miss 등의 다른 값들로 대체하겠습니다.

In [17]:
data['Initial'].replace(['Mlle','Mme','Ms','Dr','Major','Lady','Countess','Jonkheer','Col','Rev','Capt', 'Sir','Don'],
                                  ['Miss','Miss','Miss','Mr','Mr','Mrs','Mrs','Other','Other','Other','Mr','Mr','Mr'], inplace=True)
In [18]:
data.groupby('Initial')['Age'].mean() # Initial 에 따른 평균연령 체크
Out[18]:
Initial
Master     4.574167
Miss      21.860000
Mr        32.739609
Mrs       35.981818
Other     45.888889
Name: Age, dtype: float64

연령 NaN 채우기

In [19]:
## 평균의 올림 값들로 NaN 값에 할당
data.loc[(data.Age.isnull()) & (data.Initial == 'Mr') , 'Age'] = 33
data.loc[(data.Age.isnull()) & (data.Initial == 'Mrs'), 'Age'] = 36
data.loc[(data.Age.isnull()) & (data.Initial == 'Master'), 'Age'] = 5
data.loc[(data.Age.isnull()) & (data.Initial == 'Miss'), 'Age'] = 22
data.loc[(data.Age.isnull()) & (data.Initial == 'Other'), 'Age'] = 46
In [20]:
data.Age.isnull().any() # Null 값들이 완전히 제거되었습니다.
Out[20]:
False
In [21]:
f, ax = plt.subplots(1, 2, figsize=(15, 6))

data[data['Survived']==0].Age.plot.hist(ax=ax[0], bins=20, edgecolor= 'black', color ='red')
ax[0].set_title('Survived = 0')
x1 = list(range(0,85,5))
ax[0].set_xticks(x1)

data[data['Survived']==1].Age.plot.hist(ax=ax[1], bins=20, edgecolor = 'black', color='green')
ax[1].set_title('Survived = 1')
x2 = list(range(0,85,5))
ax[1].set_xticks(x2)

plt.show()

관찰결과 :

1) 5세 이하의 아이들은 많이 생존했습니다. (여성과 아이 우선)

2) 가장 고연령 탑승객도 생존했습니다. (80세)

3) 가장 많은 수의 사망자가 있는 연령 그룹은 30-40세 입니다.

In [22]:
sns.factorplot('Pclass', 'Survived', col = 'Initial', data=data)
plt.show()

각 클래스와 관계없이 여성과 아이가 우선되었다는게 명확해 보입니다.

Embarked → Categorical Value

In [23]:
pd.crosstab([data.Embarked, data.Pclass], [data.Sex, data.Survived], margins =True).style.background_gradient(cmap='summer_r')
Out[23]:
Sex female male All
Survived 0 1 0 1
Embarked Pclass
C 1 1 42 25 17 85
2 0 7 8 2 17
3 8 15 33 10 66
Q 1 0 1 1 0 2
2 0 2 1 0 3
3 9 24 36 3 72
S 1 2 46 51 28 127
2 6 61 82 15 164
3 55 33 231 34 353
All 81 231 468 109 889

탑승 항구에 따른 생존확률

In [24]:
sns.factorplot('Embarked', 'Survived', data=data)
fig = plt.gcf()
fig.set_size_inches(5, 3)
plt.show()

C항구의 생존률이 약 0.55 정도로 가장 높고, S항구가 가장 낮습니다.

In [25]:
f, ax = plt.subplots(2, 2, figsize=(15, 12))

sns.countplot('Embarked', data=data, ax=ax[0,0])
ax[0,0].set_title('No. of Passengers Boarded')

sns.countplot('Embarked', hue='Sex', data=data, ax=ax[0,1])
ax[0,1].set_title('Male-Female Split for Embarked')

sns.countplot('Embarked', hue='Survived', data=data, ax=ax[1,0])
ax[1,0].set_title('Embarked vs Survived')

sns.countplot('Embarked', hue = 'Pclass', data=data, ax=ax[1,1])
ax[1,1].set_title('Embarked vs Pclass')

plt.subplots_adjust(wspace=0.2, hspace=0.2)
plt.show()

관찰결과 :

1) S에서 가장 많은 승객이 탑승했습니다. 그리고 그 탑승객들의 대부분은 Pclass 3입니다.

2) C에서 탑승한 승객은 생존률이 높아 운이 좋아보입니다. Pclass 1과 2의 승객이기 때문일거 같습니다.

3) S항구에서 다수의 부유한 사람들이 탑승한 것 같습니다. 이 그룹의 생존률은 낮은데, 약 81%가 생존하지 못한 Pclass 3의 승객이기 때문입니다.

4) Q항구에서 탑승한 승객의 95% 가량이 Pclass 3이다.

In [26]:
sns.factorplot('Pclass', 'Survived', hue = 'Sex', col = 'Embarked', data=data)
plt.show()

관찰결과 :

1) Pclass 1과 Pclass2 여성의 생존률은 Pclass와 관계 없이 거의 1입니다.

2) S 항구에서 탑승한 Pclass 3의 탑승객은 매우 운이 없는 것 같습니다. 남성과 여성의 생존률이 모두 낮습니다. (돈이 중요한 요소입니다.)

3) Q 항구에서 탑승한 남성이 제일 불운해 보입니다. 그들 대부분이 Pclass 3 탑승객이기 때문입니다.

Embarked 의 NaN 채우기

대부분의 탑승객이 S에서 탑승했기 때문에 S로 채워주겠습니다.

In [27]:
data['Embarked'].fillna('S', inplace = True)
In [28]:
data['Embarked'].isnull().any() # NaN이 모두 제거되었습니다.
Out[28]:
False

SibSp → Discrete Feature

이 Feature는 탑승객이 혼자인지 아니면 가족과 함께 탔는지를 나타냅니다.

Sibling → 형제자매, 의붓형제자매

Spouse → 배우자

In [29]:
pd.crosstab([data.SibSp], data.Survived).style.background_gradient(cmap='summer_r')
Out[29]:
Survived 0 1
SibSp
0 398 210
1 97 112
2 15 13
3 12 4
4 15 3
5 5 0
8 7 0
In [30]:
f, ax = plt.subplots(1, 2, figsize=(15,6))

sns.barplot('SibSp', 'Survived', data=data, ax=ax[0])
ax[0].set_title('SibSp vs Survived')

sns.factorplot('SibSp', 'Survived', data=data, ax=ax[1])
ax[1].set_title('SibSp vs Survived')

plt.close(2)
plt.show()
In [31]:
pd.crosstab(data.SibSp, data.Pclass).style.background_gradient(cmap='summer_r')
Out[31]:
Pclass 1 2 3
SibSp
0 137 120 351
1 71 55 83
2 5 8 15
3 3 1 12
4 0 0 18
5 0 0 5
8 0 0 7

관찰결과 :

barplot과 factorplot을 통해 봤을 때, 승객이 혼자 탑승했을 때 생존률이 34.5% 정도입니다.
그래프의 기울기는 형제자매, 배우자의 수가 증가하면 그래프의 기울기는 감소합니다. 이해가 가는 결과 입니다.
만약, 가족과 함께 탔다면 내가 생존하기 전에 가족을 살리려고 할 것이기 때문입니다.
하지만 놀랍게도 가족의 수가 5-8명인 경우에는 생존률이 0%입니다. 이유는 아마 Pclass 때문일까요?

그 원인은 Pclass입니다. crosstab을 보면 SibSp > 3 인 경우 모두 Pclass 3에 속했습니다.
Pclass 3의 3명 초과 가족들은 모두 사망한 것이 분명합니다.

Parch

In [32]:
pd.crosstab(data.Parch, data.Pclass).style.background_gradient(cmap='summer_r')
Out[32]:
Pclass 1 2 3
Parch
0 163 134 381
1 31 32 55
2 21 16 43
3 0 2 3
4 1 0 3
5 0 0 5
6 0 0 1

crosstab을 통해 또 구성원이 많은 가족들은 Pclass3에 속함을 알 수 있습니다.

In [33]:
f, ax = plt.subplots(1, 2, figsize=(15,6))

sns.barplot('Parch', 'Survived', data=data, ax=ax[0])
ax[0].set_title('Parch vs Survived')

sns.factorplot('Parch', 'Survived', data=data, ax=ax[1])
ax[1].set_title('Parch vs Survived')

plt.close(2)
plt.show()

관찰결과 :

비슷한 결과가 나왔습니다. 부모님, 아이와 함꼐 탑승한 승객들의 생존 확률은 높았습니다.
하지만 그 수가 증가할 수록 생존률은 감소했습니다.

1-3명의 부모님, 아이와 탑승한 승객의 생존률이 좋았습니다.
혼자 탑승하는 경우, 생존하기가 어려우며, 가족이 4명이상 탑승한 경우에도 생존률은 감소했습니다.

Fare --> Continuous Feature

In [34]:
print('Highest Fare was: ', data['Fare'].max())
print('Lowest Fare was: ', data['Fare'].min())
print('Average Fare was: ', data['Fare'].mean())
Highest Fare was:  512.3292
Lowest Fare was:  0.0
Average Fare was:  32.2042079685746

가장 낮은 요금은 0원입니다.

In [35]:
f, ax = plt.subplots(1,3, figsize=(15,5))

sns.distplot(data[data['Pclass']==1].Fare, ax=ax[0])
ax[0].set_title('Fare in Pclass 1')

sns.distplot(data[data['Pclass']==2].Fare, ax=ax[1])
ax[1].set_title('Fare in Pclass 2')

sns.distplot(data[data['Pclass']==3].Fare, ax=ax[2])
ax[2].set_title('Fare in Pclass 3')
Out[35]:
Text(0.5, 1.0, 'Fare in Pclass 3')

Pclass 1 탑승객의 경우 요금 분포가 넓게 퍼져있습니다. 그리고 Pclass의 등급이 낮아질 때마다 분포는 좁아집니다. 이 변수는 연속형이기 때문에, 우리는 binning을 통해 이산형 값들로 변환해줄 것입니다.

모든 Feature들의 관찰 결과 요약 :

  • Sex : 여성의 생존확률이 남성에 비해 높았습니다.
  • Pclass :1st 클래스 탑승객의 생존률이 높은 경향을 보였습니다. Pclass 3의 생존률은 매우 낮았습니다.
    여성의 경우 Pclass 1 탑승객의 생존률은 거의 1이었고, Pclass 2의 경우에도 높았습니다. 결국 생존에는 돈이 중요했습니다.
  • Age : 5-10세보다 적은 어린이들의 생존확률이 높았습니다. 15-35세의 탑승객들은 많이 사망했습니다.
  • Embarked : 흥미로운 Feature 였습니다. 다수의 Pclass 1 탑승객이 S에서 제일 많았지만, C에서 탑승한 승객의 생존률이 더 높았습니다.
    Q에서 탑승한 승객은 거의 다 Pclass 3 에 속했습니다.
  • Parch + SibSp : 1-2명의 형제자매, 1-3명의 가족, 자녀와 함께 탑승한 경우가 혼자 탑승 또는 많은 수의 가족과 함께 탑승한 경우보다 훨씬 생존률이 높았습니다.

Correlation Between The Features

In [36]:
sns.heatmap(data.corr(), annot=True, cmap='RdYlGn',linewidths= 0.2) ## data.corr() --> 상관관계 행렬
fig = plt.gcf()
fig.set_size_inches(10, 8)
plt.show()

Heatmap의 해석

먼저 알아야 할 것은, 숫자데이터가 아닌 문자열 데이터의 상관관계는 구할 수 없다는 것입니다.
plot을 이해하기전에 상관관계가 무엇인지 보겠습니다.

  • 양의 상관관계(Positive Correlation) :
    feature A의 증가하는데 feature B가 증가한다면, 두 feature는 양의 상관관계입니다. 1 은 완전 양의 상관관계를 의미합니다.
  • 음의 상관관계(Negative Correlation) :
    feature A의 감소하는데 feature B가 증가한다면, 두 feature는 음의 상관관계입니다. -1 은 완전 음의 상관관계를 의미합니다.

두 Feature가 상당히 높은, 혹은 완전한 양의 상관관계를 가지고 있다고 하면, 한 feature값이 증가하면 다른 feature의 값도 증가합니다.
이것은 두 feature가 매우 비슷한 정보를 가지고 있으며, 그 정보간의 분산이 거의 없다는 것을 의미합니다. 이를 다중공선성(MultiColinearity)이라 합니다.

이 변수들이 redundant할 때, 우리는 그 변수를 둘 다 사용해야할까요?
모델을 만들거나 학습시킬 때, 학습시간을 줄이는 등 다른 이점을 위해 redudant한 feature는 제거되도록 해야합니다.

위의 Heatmap을 보았을 때, feature들간의 상관관계는 그렇게 높아보이지 않습니다.
가장 높은 상관관계를 지닌 두 변수는 SibSp와 Parch로 상관계수는 0.41입니다. 그렇기 때문에 모든 feature를 사용하도록 하겠습니다.

Part 2 : Feature Engineering and Data Cleansing

Feature Engineering이 무엇일까요?

feature들이 있는 dataset이 주어졌을 때, 모든 feature가 중요하진 않습니다.
제거되어야 할 redundant한 Feature가 있을 수 있습니다. 그리고 다른 feature의 관찰, 정보 추출을 통해 새로운 feature를 만들 수도 있습니다.

Name으로부터 Initial 을 만들어낸 것도 한 예입니다. 새로운 feature를 만들거나 제거해야할 Feature가 있는지 살펴보겠습니다.
그리고 예측 모델에 적합한 형태로 feature들을 변환하겠습니다.

Age_band

Problem with Age Feature:

먼저 언급했듯이, Age는 continuous feature 입니다. continuous feature의 경우, 머신러닝모델에 있어 문제가 하나 있습니다.

가령, 운동선수들을 성별로 그룹을 나눈다고 할 때, 우리는 쉽게 남성, 여셩으로 나눌 수 있습니다.

연령으로 그룹을 나눈다고 할때, 어떻게 나눌수 있을까요? 만약 30명의 사람에 30개의 연령값이 있다고 하겠습니다. 이런 경우가 문제가 됩니다.

우리는 contiunous 값을 category값으로 Binning이나 Normalization을 통해 변환해야합니다. 이번에는 binning을 통해 연령에 하나의 값을 할당하겠습니다.

최대 연령이 80세이기 떄문에, 0부터 80세까지의 연령을 5개의 bin으로 나누겠습니다. 80/5 = 16 이기 때문에, bin하나의 사이즈는 16입니다.

In [37]:
data['Age_band'] = 0 

data.loc[data['Age'] <= 16, 'Age_band'] = 0
data.loc[ (data['Age'] > 16) & (data['Age'] <=32), 'Age_band'] = 1
data.loc[ (data['Age'] > 32) & (data['Age'] <=48), 'Age_band'] = 2
data.loc[ (data['Age'] > 48) & (data['Age'] <=64), 'Age_band'] = 3
data.loc[ data['Age'] > 64, 'Age_band'] = 4

data.head(2)
Out[37]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked Initial Age_band
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S Mr 1
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C Mrs 2
In [38]:
data['Age_band'].value_counts().to_frame().style.background_gradient(cmap='summer') # 각 연령구간의 탑승객 수 체크
Out[38]:
Age_band
1 382
2 325
0 104
3 69
4 11
In [39]:
sns.factorplot('Age_band', 'Survived', data=data, col = 'Pclass')
plt.show()

Pclass와 관계없이 연령이 증가할수록 생존률이 낮아집니다.

Family_Size 와 Alone

이번에는 "Family_Size"와 "Alone" Feature를 만들어 분석하겠습니다.
이 Feature들은 Parch와 SibSp의 요약입니다. 가족의 수와 생존률의 관계를 체크하기 위한 통합된 데이터를 얻을 수 있습니다.
Alone은 승객이 혼자인지 아닌지를 나타냅니다.

In [40]:
data['Family_Size'] = 0 
data['Family_Size'] = data['Parch'] + data['SibSp'] # Family_Size 
data['Alone'] = 0
data.loc [data.Family_Size ==0, 'Alone'] = 1 # Alone
In [41]:
f, ax = plt.subplots(1, 2, figsize=(15,5))

sns.factorplot('Family_Size', 'Survived', data=data, ax=ax[0])
ax[0].set_title('Family_Size vs Survived')

sns.factorplot('Alone', 'Survived', data=data, ax=ax[1])
ax[1].set_title('Alone vs Survived')

plt.close(2)
plt.close(3)
plt.show()

Family_Size = 0 은 탑승객이 혼자임을 의미합니다. 혼자일 때, 생존률은 매우 낮습니다.
가족 수가 4명 이상일 때도 생존률은 감소합니다. 때문에 모델링에 중요한 Feature인 것 같습니다. 조금 더 분석해보겠습니다.

In [42]:
sns.factorplot('Alone', 'Survived', data=data, hue='Sex', col = 'Pclass')
plt.show()

Pclass와 무관하게 혼자 탑승한 경우는 위험합니다. 하지만 예외적으로 Pclass 3 여성 탑승객의 생존률은 가족과 함께 탑승하지 않은 경우보다 오히려 높습니다.

Fare_Range

Fare는 연속형 Feature이기 때문에, 이것을 서수형 값(Ordinal value)로 변환하겠습니다. 이 작업에pandas.qcut을 사용할 것입니다.

qcut 은 우리가 입력한 구간의 수(bin)에 따라 데이터 값을 분할 해줍니다. 가령 우리가 5개 구간을 입력하면, 5개의 구간으로 데이터 수를 균일하게 분할합니다.

In [43]:
data['Fare_Range'] = pd.qcut(data['Fare'], 4)
data.groupby(['Fare_Range'])['Survived'].mean().to_frame().style.background_gradient(cmap='summer_r')
Out[43]:
Survived
Fare_Range
(-0.001, 7.91] 0.197309
(7.91, 14.454] 0.303571
(14.454, 31.0] 0.454955
(31.0, 512.329] 0.581081

위에서 얘기한 것처럼, Fare_Range가 증가할 수록 생존률도 증가합니다.

하지만 우리는 Fare_Range를 그대로 사용할 수 없습니다. Age_Band에서 했던 것과 동일하게 하나의 값으로 변환해주어야 합니다.

In [44]:
data['Fare_cat'] = 0
data.loc[data['Fare'] <= 7.91, 'Fare_cat'] = 0
data.loc[(data['Fare'] > 7.91) & (data['Fare']<=14.454), 'Fare_cat'] = 1
data.loc[(data['Fare'] > 14.454) & (data['Fare']<=31), 'Fare_cat'] = 2
data.loc[(data['Fare'] > 31) & (data['Fare']<=513), 'Fare_cat'] = 3
In [45]:
sns.factorplot('Fare_cat', 'Survived', data=data, hue='Sex')
plt.show()

Fare_cat 이 증가할수록 생존률이 증가합니다. 이것도 Sex와 함께 모델링에 중요한 Feature가 될 것 같습니다.

문자열 값을 숫자형으로 변환하기

문자열 값을 머신러닝 모델에 사용할 수 없기 때문에, Sex, Embarked 등의 feature를 숫자값으로 변환해주어야 합니다.

In [46]:
data['Sex'