티스토리 뷰
-
분석연습에 사용된 프로그램은 "Jupyter Notebook" 입니다.
-
캐글 커널 중, "Titanic Data Science Solutions - by Manav Sehgal" 의 상당 부분을 참고하였습니다.
-
그 외에도, 다수의 블로거분들의 분석을 참고하였습니다. 링크는 아래에 기재하였습니다.
-
데이터셋은 캐글 링크를 참고해주세요.
분석 과제
타이타닉 호 침몰 사건 당시의 사망자와 생존자를 구분하는 요인 분석을 통해,
"승객들의 생존 여부를 예측하는 모델 구축"
분석에 들어가기 앞서..
특히 모델과 알고리즘을 구축하는 경우, 분석의 과정은 크게 2가지로 나뉩니다.
1. 데이터 전처리: 주어진 데이터를 파악 후, 모델에 최적화된 형태로 변형합니다.
2. 모델링: 최적화된 데이터에 모델을 적용 및 performance를 평가합니다.
이렇게 계획한 분석 Work Flow는 아래와 같습니다.
(2번과 3번 워크플로우는 다음 포스팅에서 진행됩니다.)
-
데이터 전처리
-
데이터 준비
-
데이터 변수(feature)확인
-
탐색적 데이터 분석(EDA)
-
Feature Engineering
-
-
예측 모델 구축 및 적용
-
모델 평가
1. 데이터 전처리
-
데이터 준비
-
필요한 라이브러리를 설치합니다.
#데이터 불러오기
import pandas as pd
import numpy as np
import random as rnd
#시각화
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
-
불러올 데이터셋은 다음과 같습니다.
・train.csv : 모델 학습에 사용되는 데이터
・test.csv : 모델 적용 대상이 되는 데이터
모델 적용의 일관성을 위해, train과 test를 합한 combine데이터 셋도 지정합니다.
train=pd.read_csv(".../train.csv")
test=pd.read_csv(".../test.csv")
combine=[train, test]
print(train.columns.values)
['PassengerId' 'Survived' 'Pclass' 'Name' 'Sex' 'Age' 'SibSp' 'Parch'
'Ticket' 'Fare' 'Cabin' 'Embarked']
-
데이터 변수(Feature)확인
print(train.head())
PassengerId Survived Pclass \
0 1 0 3
1 2 1 1
2 3 1 3
3 4 1 1
4 5 0 3
Name Sex Age SibSp \
0 Braund, Mr. Owen Harris male 22.0 1
1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1
2 Heikkinen, Miss. Laina female 26.0 0
3 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1
4 Allen, Mr. William Henry male 35.0 0
Parch Ticket Fare Cabin Embarked
0 0 A/5 21171 7.2500 NaN S
1 0 PC 17599 71.2833 C85 C
2 0 STON/O2. 3101282 7.9250 NaN S
3 0 113803 53.1000 C123 S
4 0 373450 8.0500 NaN S
-
예측의 대상인 목적 변수(label)은 "Survived", 나머지는 설명 변수로 작용합니다.
train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId 891 non-null int64
Survived 891 non-null int64
Pclass 891 non-null int64
Name 891 non-null object
Sex 891 non-null object
Age 714 non-null float64
SibSp 891 non-null int64
Parch 891 non-null int64
Ticket 891 non-null object
Fare 891 non-null float64
Cabin 204 non-null object
Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB
・목적 변수
"Survived": 0= 사망, 1= 생존
・설명 변수
feature명 |
scale |
Assumption |
PassengerId 승객 식별 아이디 |
nominal |
생존 여부와 큰 관련은 없을 것 ➡제거* |
Pclass 객실 등급 1st = Upper 2nd = Middle 3rd = Lower |
discrete, ordinal |
|
Name 이름 |
nominal |
|
Sex |
nominal |
생존 여부와 관련있을 것 |
Age |
continuous |
생존 여부와 관련있을 것 |
SibSp 동반 형제자매, 배우자 수 |
discrete, nominal |
➡예측 최적화된 변형 필요* |
Parch 동반 부모 자녀 수 |
discrete, nominal |
➡예측 최적화된 변형 필요* |
Ticket |
nominal |
생존 여부와 큰 관련은 없을 것 ➡제거* |
Fare 요금 |
continuous |
|
Cabin 객실 번호 |
discrete, nominal |
생존 여부와 큰 관련은 없을 것 ➡제거* |
Embarked 승선 항 |
nominal |
생존 여부와 큰 관련은 없을 것 ➡제거* |
*변수의 변형은, feature engineering단계에서 진행하도록 하겠습니다.
-
결측치(null data)를 확인합니다.
・train data
train.isnull().sum()
Out[20]:
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
결측치 존재 변수 |
결측치 수 |
Assumption |
Age |
177 |
생존 여부와 관련이 있을 것으로 예상 ➡결측치를 채우거나 변형이 필요* |
Cabin |
687 |
생존 여부와 큰 관련 없을 것으로 예상 ➡변수 제거* |
Embarked |
2 |
생존 여부와 큰 관련 없을 것으로 예상 ➡변수 제거* |
*변수의 변형은, feature engineering단계에서 진행하도록 하겠습니다.
・test data
test.isnull().sum()
Out[21]:
PassengerId 0
Pclass 0
Name 0
Sex 0
Age 86
SibSp 0
Parch 0
Ticket 0
Fare 1
Cabin 327
Embarked 0
dtype: int64
결측치 존재 변수 |
결측치 수 |
Assumption |
Age |
86 |
생존 여부와 관련이 있을 것으로 예상 ➡결측치를 채우거나 변형이 필요* |
Fare |
1 |
결측치 수가 크지 않음 ➡결측치를 채우거나 변형이 필요* |
Cabin |
327 |
생존 여부와 큰 관련 없을 것으로 예상 ➡변수 제거* |
*변수의 변형은, feature engineering단계에서 진행하도록 하겠습니다.
-
object data(category)와 non object data(non category) 묘사
-
생존 여부에 대한 설명력이 있는 변수를 예상, 살펴봅니다.
-
・object data
train.describe(include=['O'])
#or, train.describe(include=['O',"category"])
Name Sex Ticket Cabin Embarked
count 891 891 891 204 889
unique 891 2 681 147 3
top Ilmakangas, Miss. Pieta Sofia male 347082 B96 B98 S
freq 1 577 7 4 644
-
Ticket과 Cabin은 고유값(unique)의 비중이 큼 → categorical 성격 약함 →제거 확실*
-
Name은 고유값 비중이 커 categorical성격이 약하지만, miss, mr.등의 결혼 여부 표시가 포함되어 있어 변형 필요*
-
Sex: male이 대다수를 차지(891건 중, 577건)
-
Embarked: 승객 대부분이 S항에서 탑승(889건 중, 644건)
*변수의 변형은, feature engineering단계에서 진행하도록 하겠습니다.
・non object data(float, integer..)
print(train.describe())
#or,print(train.describe(exclude=['O']))
PassengerId Survived Pclass Age SibSp \
count 891.000000 891.000000 891.000000 714.000000 891.000000
mean 446.000000 0.383838 2.308642 29.699118 0.523008
std 257.353842 0.486592 0.836071 14.526497 1.102743
min 1.000000 0.000000 1.000000 0.420000 0.000000
25% 223.500000 0.000000 2.000000 20.125000 0.000000
50% 446.000000 0.000000 3.000000 28.000000 0.000000
75% 668.500000 1.000000 3.000000 38.000000 1.000000
max 891.000000 1.000000 3.000000 80.000000 8.000000
Parch Fare
count 891.000000 891.000000
mean 0.381594 32.204208
std 0.806057 49.693429
min 0.000000 0.000000
25% 0.000000 7.910400
50% 0.000000 14.454200
75% 0.000000 31.000000
max 6.000000 512.329200
-
PassengerId: 큰 관련 없어 보임 →제거 확실*
-
Survived: 대부분의 승객(75%정도)가 사망
-
Age: 대부분의 승객이 2-30대
-
Pclass: 객실 등급 중 1st는 25%미만 → 즉 대부분 2nd, 3rd 클래스
-
SibSp, Parch: 대부분의 승객이 형제, 배우자(75%정도), 혹은 부모, 자녀와 탑승하지 않음
-
Fare: 요금의 표준 편차가 가장 큼 → 즉 승객들의 요금 수준에 차이가 큼
-
요금의 최대치는 512, 하지만 대부분의 요금(75%이상)은 30, 혹은 40 언저리
-
・종합
Most of the Passengers,,, |
||||||
Survived |
Sex |
Embarked |
Age |
Pclass |
Fare |
SibSp, Parch |
사망 |
male 남성 |
S항 |
2-30대 |
낮은 클래스 |
낮은 가격대 |
동반하지 않음 |
즉, 승객의 사망 여부가 위의 7개의 변수와 관련이 있을 것이라 예상 가능합니다.
- 나머지가 이산형(discrete)혹은 범주형(categorical)변수인 것과 달리, Age와 Fare은 연속형(Continuous)변수
→Age와 Fare변수의 변형이 필요*
- 위에서 Embarked변수를 제거해야한다고 예상했던 것과는 다른 결과가 나타남
※참고
상관관계 분석
print(train.corr())
PassengerId Survived Pclass Age SibSp Parch \
PassengerId 1.000000 -0.005007 -0.035144 0.036847 -0.057527 -0.001652
Survived -0.005007 1.000000 -0.338481 -0.077221 -0.035322 0.081629
Pclass -0.035144 -0.338481 1.000000 -0.369226 0.083081 0.018443
Age 0.036847 -0.077221 -0.369226 1.000000 -0.308247 -0.189119
SibSp -0.057527 -0.035322 0.083081 -0.308247 1.000000 0.414838
Parch -0.001652 0.081629 0.018443 -0.189119 0.414838 1.000000
Fare 0.012658 0.257307 -0.549500 0.096067 0.159651 0.216225
Fare
PassengerId 0.012658
Survived 0.257307
Pclass -0.549500
Age 0.096067
SibSp 0.159651
Parch 0.216225
Fare 1.000000
※한계점 존재
-
숫자형 변수만 계산
-
라벨(Survived)과의 상관계수로만의 판단→낮은 상관계수를 가진 변수 간과 위험
-
변수 엔지니어링의 시나리오 발견 난해
*변수의 변형은, feature engineering단계에서 진행하도록 하겠습니다.
-
탐색적 데이터 분석(EDA; Explore Data Analysis)
이렇게 각 변수들의 특징 파악과 예상을 그린 후,
탐색적 데이터 분석(EDA)에서 각 변수들의 관계를 분석하고 시각화하는 과정을 통해
모델에 최적화된 변수 엔지니어링을 위한 준비를 진행합니다.
-
가장 간단한 방법은, category별 생존 여부를 집계하는 것입니다.
・범주형 변수 별 생존 평균 집계
1. 성별
ss=train[["Sex", "Survived"]].groupby(['Sex'], as_index=False).mean().sort_values(by='Survived', ascending=False)
print(ss)
ss.plot("Sex",kind="bar").set_xlabel("Sex")
Sex Survived
0 female 0.742038
1 male 0.188908
여성이 남성보다 더 많이 생존했습니다.
2. 객실 등급
ps=train[['Pclass', 'Survived']].groupby(['Pclass'], as_index=False).mean().sort_values(by='Survived', ascending=False)
print(ps)
ps.plot("Pclass",kind="bar").set_xlabel("Pclass")
Pclass Survived
0 1 0.629630
1 2 0.472826
2 3 0.242363
객실 등급이 높을 수록 더 많이 생존했습니다.
3. 동반한 형제 자매
sbs=train[["SibSp", "Survived"]].groupby(['SibSp'], as_index=False).mean().sort_values(by='Survived', ascending=False)
print(sbs)
sbs.plot("SibSp",kind="bar").set_xlabel("SibSp")
SibSp Survived
1 1 0.535885
2 2 0.464286
0 0 0.345395
3 3 0.250000
4 4 0.166667
5 5 0.000000
6 8 0.000000
뚜렷한 관계성을 알 순 없으나,
1-2명의 형제 자매를 동반한 승객이 가장 많이 생존했습니다.
4. 동반한 부모, 자녀
pcs=train[["Parch", "Survived"]].groupby(['Parch'], as_index=False).mean().sort_values(by='Survived', ascending=False)
print(pcs)
pcs.plot("Parch",kind="bar").set_xlabel("Parch")
Parch Survived
3 3 0.600000
1 1 0.550847
2 2 0.500000
0 0 0.343658
5 5 0.200000
4 4 0.000000
6 6 0.000000
뚜렷한 관계성을 알 순 없으나,
1-3명의 부모 자녀를 동반한 승객이 가장 많이 생존했습니다.
가족과 동반했는지 여부를 알 수 있는 새로운 변수를 생성한다면*
다른 결과가 나올 수도 있을 것 같습니다.
*변수의 변형은, feature engineering단계에서 진행하도록 하겠습니다.
5. 승선 항
es=train[["Embarked", "Survived"]].groupby(['Embarked'], as_index=False).mean().sort_values(by='Survived', ascending=False)
print(es)
es.plot("Embarked",kind="bar").set_xlabel("Embarked")
Embarked Survived
0 C 0.553571
1 Q 0.389610
2 S 0.336957
S에서 승선한 사람은 낮은, C에서 승선한 사람은 높은 생존 평균을 보이고 있지만,
승선한 항구를 요인으로 보기에는 어려워보입니다.
다른 변수와의 결합을 통한 생존 여부를 살펴볼 필요가 있습니다.
5.1 승선 항과 객실 등급
sns.countplot('Embarked', hue='Pclass', data=train)
C의 객실 등급 중 1st가 가장 많이 차지하는 것이 C의 높은 생존 평균을,
S의 객실 등급 중 3rd가 가장 많이 차지하는 것이 S의 낮은 생존 평균을 설명할 수도 있을 것 같습니다.
・연속적 변수 별 생존 집계
연속적인 성격을 지니고 있기에 group by가 아닌 히스토그램을 적용합니다.
1. 나이
g = sns.FacetGrid(train, col='Survived')
g.map(plt.hist, 'Age', bins=20)
생존자 중 나이가 어린 층이 많다는 걸 알 수 있지만, ( Survived=1 그래프에서 오른쪽으로 약간 비대칭)
사망자의 그래프(Survived=0)도 그다지 다르지 않습니다.
결측치가 존재하고(82건), 연속적 변수이므로 범주형 번수로의 변형* 및 다중 변수 비교 등이 필요합니다.
*변수의 변형은, feature engineering단계에서 진행하도록 하겠습니다.
1.1 다중 변수 비교(categorical변수와의 결합) ; 나이, 객실 등급
생존 구분이 비교적 명확한 categorical변수와의 결합을 통해 Continuous변수의 설명력 보유 여부를 살펴봅니다.
grid = sns.FacetGrid(train, col='Survived', row='Pclass', size=2.2, aspect=1.6)
grid.map(plt.hist, 'Age', alpha=.5, bins=20)
grid.add_legend();
- 객실 등급 1st : 생존이 많으며, 비교적 대칭적입니다.
- 객실 등급 2nd : 생존과 사망이 거의 균등하며, 생존 중 0-10세 연령층이 증가하였습니다.
- 객실 등급 3nd : 대부분 사망하였지만, 어린 연령층의 생존이 나타납니다.
즉, 낮은 객실 등급은 대부분 사망함에도 불구, "어린 나이"의 승객들은 생존하였고
나이와 생존의 관계성이 명확해짐을 알 수 있습니다.
2. 요금
f = sns.FacetGrid(train, col='Survived')
f.map(plt.hist, 'Fare', bins=10)
요금이 높을 수록 생존한다는 예상은 틀려보이지만,
객실 등급(Pclass)과 반대 경향이 나타나는 것이 이상합니다. 심한 비대칭 또한 보입니다.
결측치가 존재하고(1건), 연속적 변수이므로 범주형 변수로의 변형*및 다중 변수 비교 등이 필요합니다.
*변수의 변형은, feature engineering단계에서 진행하도록 하겠습니다.
2.1 다중 변수 비교(categorical변수와의 결합) ; 요금, 성별, 승선 항
#요금의 Central Tendency(평균, 최빈치, 중앙값 등)을 나타냅니다.
grid = sns.FacetGrid(train, row='Embarked', col='Survived', size=2.2, aspect=1.6)
grid.map(sns.barplot, 'Sex', 'Fare', alpha=.5, ci=None)
grid.add_legend()
Survived=1에서의 요금이 Survived=0보다 높습니다.
승선 항 C의 요금이 다른 항구보다 높고,
1st 및 생존여부가 많았던 것과 관련이 있을 것 같습니다.
-
Feature Engineering
탐색적 데이터 분석(EDA)에서 살펴본 것과 같이 변수의 변형을 진행해보도록 하겠습니다.
변수의 변형은 train과 test데이터의 일관성 보장을 위해, combine데이터셋으로 진행합니다.
변형이 필요한 변수 |
변형 내용 |
전반적 변수 |
모델 적용에 최적화된 숫자형 변수로 변형 |
PassengerId |
변수 제거 |
Name |
숫자 범주형 변수로의 변형(정수 인코딩) |
Sex |
숫자 범주형 변수로의 변형(정수 인코딩; 원 핫 인코딩) |
Age |
결측치 채우기 숫자 범주형 변수로의 변형(정수 인코딩) |
SibSp,Parch |
새로운 변수로의 통합(정수 인코딩; 원 핫 인코딩) |
Ticket |
변수 제거 |
Fare |
결측치 채우기 숫자 범주형 변수로의 변형(정수 인코딩) |
Cabin |
변수 제거 |
Embarked |
결측치 채우기 숫자 범주형 변수로의 변형(정수 인코딩) |
・변수 Ticket, Cabin
변수를 제거합니다.
print("Before", train.shape, test.shape, combine[0].shape, combine[1].shape)
train= train.drop(['Ticket', 'Cabin'], axis=1)
test= test.drop(['Ticket', 'Cabin'], axis=1)
combine = [train, test]
"After", train.shape, test.shape, combine[0].shape, combine[1].shape
Before (891, 12) (418, 11) (891, 12) (418, 11)
Out[4]:
('After', (891, 10), (418, 9), (891, 10), (418, 9))
・변수 Name
먼저 범주형 변수로의 변형을 위해 Title이라는 새로운 변수를 만들어냅니다.
그 후 정규식과 성별과의 통합을 통해 범주 구분을 시도합니다.
for dataset in combine:
dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\.', expand=False)
print(pd.crosstab(train['Title'], train['Sex']))
Sex female male
Title
Capt 0 1
Col 0 2
Countess 1 0
Don 0 1
Dr 1 6
Jonkheer 0 1
Lady 1 0
Major 0 2
Master 0 40
Miss 182 0
Mlle 2 0
Mme 1 0
Mr 0 517
Mrs 125 0
Ms 1 0
Rev 0 6
Sir 0 1
- female에서는 Miss와 Mrs가, male에서는 Master와 Mr가 두드러지게 나타납니다.
(Mlle와 Ms 는 Miss의, Ms는 Mrs의 불어식 표현)
- 나머지는 Rare로 분류합니다.
for dataset in combine:
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')
print(train[['Title', 'Survived']].groupby(['Title'], as_index=False).mean())
Title Survived
0 Master 0.575000
1 Miss 0.702703
2 Mr 0.156673
3 Mrs 0.793651
4 Rare 0.347826
Title변수를 숫자형 변수로 바꿔줍니다.
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}
for dataset in combine:
dataset['Title'] = dataset['Title'].map(title_mapping)
dataset['Title'] = dataset['Title'].fillna(0)
print(train.head())
PassengerId Survived Pclass \
0 1 0 3
1 2 1 1
2 3 1 3
3 4 1 1
4 5 0 3
Name Sex Age SibSp \
0 Braund, Mr. Owen Harris male 22.0 1
1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1
2 Heikkinen, Miss. Laina female 26.0 0
3 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1
4 Allen, Mr. William Henry male 35.0 0
Parch Fare Embarked Title
0 0 7.2500 S 1
1 0 71.2833 C 3
2 0 7.9250 S 2
3 0 53.1000 S 3
4 0 8.0500 S 1
・변수 PassengerId, name
이제 Name변수를 제거할 수 있습니다.
PassengerId변수도 같이 제거합니다.
train = train.drop(['Name', 'PassengerId'], axis=1)
test = test.drop(['Name'], axis=1)
combine = [train, test]
#test데이터셋에는 PassegnerId변수가 없습니다.
print(train.shape, test.shape)
(891, 9) (418, 9)
・변수 Sex
숫자 범주형 변수로 바꿔줍니다.
+0과 1로 변형시키는 것을 원 핫 인코딩(one-hot encoding)이라고도 부릅니다.
for dataset in combine:
dataset['Sex'] = dataset['Sex'].map( {'female': 1, 'male': 0} ).astype(int)
print(train.head())
Survived Pclass Sex Age SibSp Parch Fare Embarked Title
0 0 3 0 22.0 1 0 7.2500 S 1
1 1 1 1 38.0 1 0 71.2833 C 3
2 1 3 1 26.0 0 0 7.9250 S 2
3 1 1 1 35.0 1 0 53.1000 S 3
4 0 3 0 35.0 0 0 8.0500 S 1
・변수 Age
결측치를 채워줍니다.
다른 변수와 결합 시의 추측되는 Age중앙값으로 대체하겠습니다.
EDA단계에서의 객실 등급(Pclass)과의 관계성을 근거로, 이번에는 Sex변수를 열로 잡겠습니다.
먼저, 시각화해봅니다.
grid = sns.FacetGrid(train, row='Pclass', col='Sex', size=2.2, aspect=1.6)
grid.map(plt.hist, 'Age', alpha=.5, bins=20)
grid.add_legend()
Pclass, Sex와 Age와의 결합이 2열 3행으로 구성됨을 알 수 있습니다.
guess_ages = np.zeros((2,3))
for dataset in combine:
for i in range(0, 2):
for j in range(0, 3):
guess_df = dataset[(dataset['Sex'] == i) & \
(dataset['Pclass'] == j+1)]['Age'].dropna()
# 위에서 guess_ages사이즈를 [2,3]으로 잡아뒀으므로 j의 범위도 이를 따릅니다.
age_guess = guess_df.median()
# age의 random값의 소수점을 .5에 가깝도록 변형시킵니다.
guess_ages[i,j] = int( age_guess/0.5 + 0.5 ) * 0.5
for i in range(0, 2):
for j in range(0, 3):
dataset.loc[ (dataset.Age.isnull()) & (dataset.Sex == i) & (dataset.Pclass == j+1),\
'Age'] = guess_ages[i,j]
dataset['Age'] = dataset['Age'].astype(int)
train.isnull().sum()
Age의 결측치가 채워진 것을 확인할 수 있습니다.
Survived 0
Pclass 0
Sex 0
Age 0
SibSp 0
Parch 0
Fare 0
Embarked 2
Title 0
dtype: int64
이제 범주형 변수로 바꿔줍니다.
생존 평균으로 그룹화된 변수 "AgeBand"를 생성합니다.
train['AgeBand'] = pd.cut(train['Age'], 5)
#임의로 5개의 그룹을 지정합니다.
print(train[['AgeBand', 'Survived']].groupby(['AgeBand'], as_index=False).mean().sort_values(by='AgeBand', ascending=True))
AgeBand Survived
0 (-0.08, 16.0] 0.550000
1 (16.0, 32.0] 0.337374
2 (32.0, 48.0] 0.412037
3 (48.0, 64.0] 0.434783
4 (64.0, 80.0] 0.090909
AgeBand를 바탕으로 Age를 범주형 변수로 바꿔준 후, AgeBand변수는 제거합니다.
for dataset in combine:
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']
train = train.drop(['AgeBand'], axis=1)
combine = [train, test]
print(train.head())
Survived Pclass Sex Age SibSp Parch Fare Embarked Title
0 0 3 0 0 1 0 7.2500 S 1
1 1 1 1 0 1 0 71.2833 C 3
2 1 3 1 0 0 0 7.9250 S 2
3 1 1 1 0 1 0 53.1000 S 3
4 0 3 0 0 0 0 8.0500 S 1
+ 추가로 참고한 커널은 Age변수와 Pclass를 곱한 Age*Class변수도 생성하였습니다.
EDA단계에서 Pclass와 결합 시, Age의 생존 여부에 대한 설명력이 증가한 것에 근거하였다고 추측할 수 있습니다.
for dataset in combine:
dataset['Age*Class'] = dataset.Age * dataset.Pclass
print(train.loc[:, ['Age*Class', 'Age', 'Pclass']].head(3))
Age*Class Age Pclass
0 3 1 3
1 2 2 1
2 3 1 3
・변수 SibSp,Parch
가족과의 동반여부를 알 수 있는 새로운 변수로 통합시킵니다.
for dataset in combine:
dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1
#자기 자신을 포함시킵니다.
print(train[['FamilySize', 'Survived']].groupby(['FamilySize'], as_index=False).mean().sort_values(by='Survived', ascending=False))
FamilySize Survived
3 4 0.724138
2 3 0.578431
1 2 0.552795
6 7 0.333333
0 1 0.303538
4 5 0.200000
5 6 0.136364
7 8 0.000000
8 11 0.000000
FamilySize=1는 가족과 동반하지 않았음을 의미하여,
1은 동반X, 0은 동반했다는 새로운 변수 IsAlone을 생성합니다.
for dataset in combine:
dataset['IsAlone'] = 0
dataset.loc[dataset['FamilySize'] == 1, 'IsAlone'] = 1
print(train[['IsAlone', 'Survived']].groupby(['IsAlone'], as_index=False).mean())
IsAlone Survived
0 0 0.505650
1 1 0.303538
이제 SibSp, Parch, FamilySize변수를 제거합니다.
train = train.drop(['Parch', 'SibSp', 'FamilySize'], axis=1)
test = test.drop(['Parch', 'SibSp', 'FamilySize'], axis=1)
combine = [train, test]
・변수 Embarked
결측치가 2개밖에 되지 않으므로, 간단히 최빈값으로 대체합니다.
그 후 숫자 범주형 변수로 바꿔줍니다.
(EDA에서 승선 항에 따라 생존 평균값이 달라지고 이는 Pclass에 따른 것임을 확인하였으므로.
Ordinal성격을 띄는 변수, 즉 생존 평균값이 높은 순서대로 C=2, Q=1, S=0을 부여할 것 같았지만 그렇지 않았습니다. )
freq_port = train.Embarked.dropna().mode()[0] # "S"
for dataset in combine:
dataset['Embarked'] = dataset['Embarked'].fillna(freq_port)
dataset['Embarked'] = dataset['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int)
・변수 Fare
test데이터셋에서 결측치는 1개밖에 존재하지 않으므로, 이번에는 간단히 중앙값으로 대체합니다.
test['Fare'].fillna(test['Fare'].dropna().median(), inplace=True)
그 후 숫자 범주형 변수로 바꿔줍니다.
방법은 Age와 동일합니다.
train['FareBand'] = pd.qcut(train['Fare'], 4)
print(train[['FareBand', 'Survived']].groupby(['FareBand'], as_index=False).mean().sort_values(by='FareBand', ascending=True))
FareBand Survived
0 (-0.001, 7.91] 0.197309
1 (7.91, 14.454] 0.303571
2 (14.454, 31.0] 0.454955
3 (31.0, 512.329] 0.581081
for dataset in combine:
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)
train = train.drop(['FareBand'], axis=1)
combine = [train, test]
이렇게 해서 준비된 train데이터셋은 다음과 같습니다.
print(train.head(3))
Survived Pclass Sex Age Fare Embarked Title IsAlone Age*Class
0 0 3 0 1 0 0 1 0 3
1 1 1 1 2 0 1 3 0 2
2 1 3 1 1 0 0 2 1 3
이렇게 데이터 준비가 완료되었습니다.
번거러워보이지만, 필수적인 단계입니다.
모델 적용 및 평가는 다음 포스팅에서 진행됩니다.
참고
캐글 커널: Titanic Data Science Solutions - by Manav Sehgal
캐글 데이터 분석 리뷰 블로그: https://kaggle-kr.tistory.com/17
'데이터분석 > 분석 연습' 카테고리의 다른 글
Kaggle 캐글 연습#1_Titanic 타이타닉 생존자 예측_2/2 (0) | 2019.05.13 |
---|
- Total
- Today
- Yesterday
- 상관관계
- 사분위수
- 분당서울대병원
- 코딩테스트
- programmers
- 파이썬
- leatcode
- hash
- 중앙값
- 조건부확률
- TensorFlow
- 뇌하수체
- 분산
- 쿠싱
- 쿠싱증후군
- Python
- neural network
- random forest
- counter
- 통계
- 평균
- Lambda
- 군고구마
- 힙
- SQL
- 프로그래머스
- 확률
- 확률분포
- 상대도수
- 뇌하수체선종
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |