인공지능/머신러닝

Kaggle 타이타닉(문제 정의~데이터 전처리)

백관구 2020. 7. 22. 00:45
반응형
 

문제 정의

  • 1912년 4월 15일 타이타닉 호가 북대서양 해상에서 유빙과 충돌해 가라앉는 사고가 발생
  • 전체 2224 명의 승객들 중 1502 명의 사망자를 기록 (32% 생존율)
  • 높은 사망율은 부족한 구명선 때문
  • 특정 그룹(예: 어린이, 상류층)의 생존율이 비교적 높았음
  • 문제: 타이타닉 승객 정보를 이용해 타이타닉 사고로 인한 생존/사망 여부를 예측하는 것이 목적
  • 훈련 자료: 타이타닉에 승선한 승객 정보와 사고로 인한 생존/사망 여부의 정보
  • 테스트 자료: 오직 승객 정보만
 

훈련, 테스트 자료 정의

 

훈련, 테스트 자료 불러오기 & 사용 가능한 변수 확인

In [1]:
import pandas as pd

train_df = pd.read_csv("./DATA/train.csv")
test_df  = pd.read_csv("./DATA/test.csv")

print(train_df.columns.values)
 
['PassengerId' 'Survived' 'Pclass' 'Name' 'Sex' 'Age' 'SibSp' 'Parch'
 'Ticket' 'Fare' 'Cabin' 'Embarked']
 
  • 범주형

    • 명목형: 생존 여부(Survived), 성별(Sex), 객실(Cabin), 승선지(Embarked)
    • 순서형: 티켓 클래스(Pclass)
  • 수치형

    • 이산형: 연령(Age), 함께 승선한 형제자매와 배우자의 수(SibSp), 함께 승선한 부모와 자식의 수(Parch)
    • 연속형: 요금(Fare)
 

훈련 자료 정보

In [2]:
train_df.info()
 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
 
  • 훈련 자료의 결측 개수: Cabin (687) > Age (177) > Embarked (2)
 

테스트 자료 정보

In [3]:
test_df.info()
 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 11 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  418 non-null    int64  
 1   Pclass       418 non-null    int64  
 2   Name         418 non-null    object 
 3   Sex          418 non-null    object 
 4   Age          332 non-null    float64
 5   SibSp        418 non-null    int64  
 6   Parch        418 non-null    int64  
 7   Ticket       418 non-null    object 
 8   Fare         417 non-null    float64
 9   Cabin        91 non-null     object 
 10  Embarked     418 non-null    object 
dtypes: float64(2), int64(4), object(5)
memory usage: 36.0+ KB
 
  • 테스트 자료의 결측 개수: Cabin (327) > Age (86) > Fare (1)
 

훈련 자료 확인

In [4]:
train_df.head()
Out[4]:
 PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked
0103Braund, Mr. Owen Harrismale22.010A/5 211717.2500NaNS
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.010PC 1759971.2833C85C
2313Heikkinen, Miss. Lainafemale26.000STON/O2. 31012827.9250NaNS
3411Futrelle, Mrs. Jacques Heath (Lily May Peel)female35.01011380353.1000C123S
4503Allen, Mr. William Henrymale35.0003734508.0500NaNS
In [5]:
train_df.tail()
Out[5]:
 PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked
88688702Montvila, Rev. Juozasmale27.00021153613.00NaNS
88788811Graham, Miss. Margaret Edithfemale19.00011205330.00B42S
88888903Johnston, Miss. Catherine Helen "Carrie"femaleNaN12W./C. 660723.45NaNS
88989011Behr, Mr. Karl Howellmale26.00011136930.00C148C
89089103Dooley, Mr. Patrickmale32.0003703767.75NaNQ
 

데이터 분석

 

훈련 자료 int, float 변수 통계치

In [6]:
train_df.describe()
Out[6]:
 PassengerIdSurvivedPclassAgeSibSpParchFare
count891.000000891.000000891.000000714.000000891.000000891.000000891.000000
mean446.0000000.3838382.30864229.6991180.5230080.38159432.204208
std257.3538420.4865920.83607114.5264971.1027430.80605749.693429
min1.0000000.0000001.0000000.4200000.0000000.0000000.000000
25%223.5000000.0000002.00000020.1250000.0000000.0000007.910400
50%446.0000000.0000003.00000028.0000000.0000000.00000014.454200
75%668.5000001.0000003.00000038.0000001.0000000.00000031.000000
max891.0000001.0000003.00000080.0000008.0000006.000000512.329200
 
  • 훈련 자료 샘플 수: 891 (count = 891)
  • 훈련 자료 샘플 내 생존율: 38.4% (mean of Survived = 0.384)
 

훈련 자료 object 변수 통계치

In [7]:
train_df.describe(include = ["O"])
Out[7]:
 NameSexTicketCabinEmbarked
count891891891204889
unique89126811473
topLeader, Dr. Alice (Farnham)maleCA. 2343G6S
freq157774644
 
  • 훈련 자료 남성 수: 577 명(top = male, freq = 577)
  • 훈련 자료 가장 많은 승선지: S, 644 명(top = S, freq = 644)
 

훈련 자료에서 티켓 클래스에 따른 생존율 비교

In [8]:
train_df[["Pclass", "Survived"]].groupby(["Pclass"], as_index = False).mean().sort_values(by = "Survived", ascending = False)
# groupby에 as_index를 False로 하면 Pclass를 index로 사용하지 않음, ascending: 오름차순
Out[8]:
 PclassSurvived
010.629630
120.472826
230.242363
 
  • 티켓 클래스가 좋을수록 생존율이 높음
In [9]:
train_df[["Pclass", "Survived"]].groupby(["Pclass"], as_index = True).mean().sort_values(by = "Survived", ascending = False)
# as_index를 True로 하면 Pclass를 index로 사용
Out[9]:
 Survived
Pclass 
10.629630
20.472826
30.242363
 

훈련 자료에서 성별에 따른 생존율 비교

In [10]:
train_df[["Sex", "Survived"]].groupby(["Sex"], as_index = False).mean().sort_values(by = "Survived", ascending = False)
Out[10]:
 SexSurvived
0female0.742038
1male0.188908
 
  • 여성의 생존율이 남성보다 높음
 

훈련 자료에서 함께 승선한 형제자매와 배우자 수에 따른 생존율 비교

In [11]:
train_df[["SibSp", "Survived"]].groupby(["SibSp"], as_index = False).mean().sort_values(by = "Survived", ascending = False)
Out[11]:
 SibSpSurvived
110.535885
220.464286
000.345395
330.250000
440.166667
550.000000
680.000000
 

훈련 자료에서 함께 승선한 부모와 자식 수에 따른 생존율 비교

In [12]:
train_df[["Parch", "Survived"]].groupby(["Parch"], as_index = False).mean().sort_values(by = "Survived", ascending = False)
Out[12]:
 ParchSurvived
330.600000
110.550847
220.500000
000.343658
550.200000
440.000000
660.000000
 
  • 동행이 적은 경우 생존율이 높음
 

훈련 자료에서 생존 여부에 따른 연령 분포

In [13]:
import seaborn as sns
import matplotlib.pyplot as plt

g = sns.FacetGrid(train_df, col = "Survived") # 열(col)을 생존 여부로 나눔
g.map(plt.hist, "Age", bins = 20) # 히스토그램으로 시각화, 연령의 분포를 확인, 히스토그램 bin을 20개로 설정
Out[13]:
<seaborn.axisgrid.FacetGrid at 0x294d4b9e448>
 
 
  • 4세 이하의 유아의 생존율이 높음
  • 15~25세 승객들의 생존율이 낮음
 

훈련 자료에서 티켓 등급과 생존 여부에 따른 연령 분포

In [14]:
g = sns.FacetGrid(train_df, col = "Survived", row = "Pclass", hue = "Pclass", height = 2.2, aspect = 1.6)
# 열을 생존 여부, 행(row)과 색깔(hue)을 티켓 클래스로 나눔, width = height * aspect
g.map(plt.hist, "Age", alpha = 0.5, bins = 20) # 투명도(alpha): 0.5
g.add_legend() # 범례 추가
Out[14]:
<seaborn.axisgrid.FacetGrid at 0x294d790f288>
 
 
  • 티켓 등급이 3등급인 경우, 승객 수는 가장 많고, 생존율도 가장 낮음
  • 티켓 등급이 2등급인 유아는 대부분 생존함
  • 티켓 등급이 1등급인 경우 생존율이 비교적 높음
 

훈련 자료에서 승선지와 티켓 등급에 따른 생존율

In [15]:
g = sns.FacetGrid(train_df, col = "Embarked", height = 2.2, aspect = 1.6)
g.map(sns.pointplot, "Pclass", "Survived", "Sex", palette = "deep", order = [1, 2, 3], hue_order = ["male", "female"])
# Pointplot으로 시각화, x: 티켓 등급, y: 생존 여부, 색깔: 성별, x축 순서: [1, 2, 3], 색깔 순서: [남성, 여성]
g.add_legend()
Out[15]:
<seaborn.axisgrid.FacetGrid at 0x294d7cf21c8>
 
 
  • Error bar는 1표준 편차
  • 승선지가 C와 Q인 경우, 남성의 티켓 등급이 3등급일 때 2등급보다 생존율이 높을 가능성이 있음
 

훈련 자료에서 승선지, 생존 여부, 성별에 따른 요금

In [16]:
g = sns.FacetGrid(train_df, row = "Embarked", col = "Survived", hue = "Sex", height = 2.2, aspect = 1.6)
g.map(sns.barplot, "Sex", "Fare", alpha = 0.5, ci = None, order = ["male", "female"])
# 바그래프로 시각화, x: 성별, y: 요금, Error bar: 표시 안 함
g.add_legend()
Out[16]:
<seaborn.axisgrid.FacetGrid at 0x294d7e9bec8>
 
 
  • 승선지가 S 또는 C인 경우, 생존한 승객들의 평균 요금이 비교적 높음
 

데이터 전처리

 

안 쓸 변수(Ticket, Cabin) 제거

In [17]:
print("Before", train_df.shape, test_df.shape)

train_df = train_df.drop(["Ticket", "Cabin"], axis = 1) # 열(axis = 1) 제거
test_df  =  test_df.drop(["Ticket", "Cabin"], axis = 1)

print("After", train_df.shape, test_df.shape)
 
Before (891, 12) (418, 11)
After (891, 10) (418, 9)
 

이름에서 칭호만 추출해서 Title 열에 저장

In [18]:
train_df["Name"]
Out[18]:
0                                Braund, Mr. Owen Harris
1      Cumings, Mrs. John Bradley (Florence Briggs Th...
2                                 Heikkinen, Miss. Laina
3           Futrelle, Mrs. Jacques Heath (Lily May Peel)
4                               Allen, Mr. William Henry
                             ...                        
886                                Montvila, Rev. Juozas
887                         Graham, Miss. Margaret Edith
888             Johnston, Miss. Catherine Helen "Carrie"
889                                Behr, Mr. Karl Howell
890                                  Dooley, Mr. Patrick
Name: Name, Length: 891, dtype: object
In [19]:
train_df["Title"] = train_df.Name.str.extract("([A-Za-z]+)\.", expand = False)
test_df["Title"]  =  test_df.Name.str.extract("([A-Za-z]+)\.", expand = False)
# 알파벳으로 되어있고 .으로 찍힌 패턴 추출, expand = False면 Series 리턴
train_df
Out[19]:
 PassengerIdSurvivedPclassNameSexAgeSibSpParchFareEmbarkedTitle
0103Braund, Mr. Owen Harrismale22.0107.2500SMr
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.01071.2833CMrs
2313Heikkinen, Miss. Lainafemale26.0007.9250SMiss
3411Futrelle, Mrs. Jacques Heath (Lily May Peel)female35.01053.1000SMrs
4503Allen, Mr. William Henrymale35.0008.0500SMr
....................................
88688702Montvila, Rev. Juozasmale27.00013.0000SRev
88788811Graham, Miss. Margaret Edithfemale19.00030.0000SMiss
88888903Johnston, Miss. Catherine Helen "Carrie"femaleNaN1223.4500SMiss
88989011Behr, Mr. Karl Howellmale26.00030.0000CMr
89089103Dooley, Mr. Patrickmale32.0007.7500QMr

891 rows × 11 columns

 

빈도표 만들기

In [20]:
pd.crosstab(train_df["Title"], train_df["Sex"]) # 행: 칭호, 열: 성별
Out[20]:
Sexfemalemale
Title  
Capt01
Col02
Countess10
Don01
Dr16
Jonkheer01
Lady10
Major02
Master040
Miss1820
Mlle20
Mme10
Mr0517
Mrs1250
Ms10
Rev06
Sir01
 

드문 칭호를 바꾸기

In [21]:
train_df["Title"] = train_df["Title"].replace(["Capt", "Col", "Don", "Jonkheer", "Major", "Rev", "Sir"], "MaleRare")
# 훈련 자료에서 "Capt", "Col", "Don", "Jonkheer", "Major", "Rev", "Sir" 칭호를 "MaleRare"로 교체
train_df["Title"] = train_df["Title"].replace(["Countess", "Lady", "Mlle", "Mme", "Ms"], "FemaleRare")
train_df["Title"] = train_df["Title"].replace(["Dr"], "Rare")

test_df["Title"] = test_df["Title"].replace(["Capt", "Col", "Don", "Jonkheer", "Major", "Rev", "Sir"], "MaleRare")
test_df["Title"] = test_df["Title"].replace(["Countess", "Lady", "Mlle", "Mme", "Ms"], "FemaleRare")
test_df["Title"] = test_df["Title"].replace(["Dr"], "Rare")

train_df
Out[21]:
 PassengerIdSurvivedPclassNameSexAgeSibSpParchFareEmbarkedTitle
0103Braund, Mr. Owen Harrismale22.0107.2500SMr
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.01071.2833CMrs
2313Heikkinen, Miss. Lainafemale26.0007.9250SMiss
3411Futrelle, Mrs. Jacques Heath (Lily May Peel)female35.01053.1000SMrs
4503Allen, Mr. William Henrymale35.0008.0500SMr
....................................
88688702Montvila, Rev. Juozasmale27.00013.0000SMaleRare
88788811Graham, Miss. Margaret Edithfemale19.00030.0000SMiss
88888903Johnston, Miss. Catherine Helen "Carrie"femaleNaN1223.4500SMiss
88989011Behr, Mr. Karl Howellmale26.00030.0000CMr
89089103Dooley, Mr. Patrickmale32.0007.7500QMr

891 rows × 11 columns

 

훈련 자료에서 칭호에 따른 생존율

In [22]:
train_df[["Title", "Survived"]].groupby(["Title"], as_index = False).mean().sort_values(by = "Survived", ascending = False)
Out[22]:
 TitleSurvived
0FemaleRare1.000000
5Mrs0.792000
3Miss0.697802
2Master0.575000
6Rare0.428571
1MaleRare0.214286
4Mr0.156673
 
  • 여성 칭호(FemaleRare, Mrs, Miss)를 가진 승객의 생존율이 비교적 높음
 

칭호를 숫자로 변환

In [23]:
title_mapping = {"FemaleRare": 1, "Mrs": 2, "Miss": 3, "Master": 4, "Rare": 5, "MaleRare": 6, "Mr": 7} # 각 칭호에 매칭할 숫자

train_df["Title"] = train_df["Title"].map(title_mapping)
train_df["Title"] = train_df["Title"].fillna(0) # NaN (Null) 값을 0으로 채움

test_df["Title"] = test_df["Title"].map(title_mapping)
test_df["Title"] = test_df["Title"].fillna(0)

train_df
Out[23]:
 PassengerIdSurvivedPclassNameSexAgeSibSpParchFareEmbarkedTitle
0103Braund, Mr. Owen Harrismale22.0107.2500S7
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.01071.2833C2
2313Heikkinen, Miss. Lainafemale26.0007.9250S3
3411Futrelle, Mrs. Jacques Heath (Lily May Peel)female35.01053.1000S2
4503Allen, Mr. William Henrymale35.0008.0500S7
....................................
88688702Montvila, Rev. Juozasmale27.00013.0000S6
88788811Graham, Miss. Margaret Edithfemale19.00030.0000S3
88888903Johnston, Miss. Catherine Helen "Carrie"femaleNaN1223.4500S3
88989011Behr, Mr. Karl Howellmale26.00030.0000C7
89089103Dooley, Mr. Patrickmale32.0007.7500Q7

891 rows × 11 columns

 

안 쓸 변수(이름, 고객 번호) 제거

In [24]:
print("Before", train_df.shape, test_df.shape)

train_df = train_df.drop(["Name", "PassengerId"], axis = 1)
test_df  =  test_df.drop(["Name"], axis = 1)

print("After", train_df.shape, test_df.shape)
 
Before (891, 11) (418, 10)
After (891, 9) (418, 9)
 

성별을 숫자로 변환

In [25]:
sex_mapping = {"male": 0, "female": 1}

train_df["Sex"] = train_df["Sex"].map(sex_mapping).astype(int)
test_df["Sex"]  =  test_df["Sex"].map(sex_mapping).astype(int)

train_df.head()
Out[25]:
 SurvivedPclassSexAgeSibSpParchFareEmbarkedTitle
003022.0107.2500S7
111138.01071.2833C2
213126.0007.9250S3
311135.01053.1000S2
403035.0008.0500S7
 

연령 결측값 보완

  • 방법: 연령과 관련된 성별, 티켓 등급을 이용해 연령을 추정 (중앙값)
 

성별, 티켓 등급별 연령 분포 확인

In [26]:
g = sns.FacetGrid(train_df, row = "Sex", col = "Pclass", hue = "Sex", height = 2.2, aspect = 1.6)
g.map(plt.hist, "Age", alpha = 0.5, bins = 20)
g.add_legend()
Out[26]:
<seaborn.axisgrid.FacetGrid at 0x294d80ffc48>
 
 

훈련 자료에서 성별, 티켓 등급별 연령 중앙값 계산

In [27]:
import numpy as np

guess_ages = np.zeros((2, 3)) # 성별(2), 티켓 등급별(3) 연령 추정 표

for i in range(guess_ages.shape[0]):
    for j in range(guess_ages.shape[1]):
        guess_df = train_df[(train_df["Sex"] == i) & (train_df["Pclass"] == j + 1)]["Age"].dropna()
        # 훈련 자료에서 성별이 i이고 티켓 등급이 j+1인 연령 추출하고 결측은 제외
        age_guess = guess_df.median() # 추출한 연령 집단의 중앙값
        guess_ages[i, j] = round(age_guess) # 소수점 반올림해서 연령 추정 표 채우기

guess_ages
Out[27]:
array([[40., 30., 25.],
       [35., 28., 22.]])
 
  • 각 티켓 등급별로 중앙값을 비교해보면, 남성이 여성보다 연령이 높음
  • 티켓 등급이 좋을수록 연령 중앙값이 높음
 

연령 결측 보완

In [28]:
for i in range(guess_ages.shape[0]):
    for j in range(guess_ages.shape[1]):
        train_df.loc[(train_df["Age"].isnull()) & (train_df["Sex"] == i) & (train_df["Pclass"] == j + 1), "Age"] = guess_ages[i, j]
        # 훈련 자료에서 연령이 결측, 성별이 i, 티켓 등급이 j+1인 샘플의 연령에 해당하는 추정된 연령 채우기
        test_df.loc[ ( test_df["Age"].isnull()) & ( test_df["Sex"] == i) & ( test_df["Pclass"] == j + 1), "Age"] = guess_ages[i, j]
        
train_df["Age"] = train_df["Age"].astype(int) # 연령을 정수형으로 변환
test_df[ "Age"] =  test_df["Age"].astype(int)

train_df.info()
 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 9 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   Survived  891 non-null    int64  
 1   Pclass    891 non-null    int64  
 2   Sex       891 non-null    int32  
 3   Age       891 non-null    int32  
 4   SibSp     891 non-null    int64  
 5   Parch     891 non-null    int64  
 6   Fare      891 non-null    float64
 7   Embarked  889 non-null    object 
 8   Title     891 non-null    int64  
dtypes: float64(1), int32(2), int64(5), object(1)
memory usage: 55.8+ KB
 
  • 연령 결측값이 채워짐을 확인
 

연령대별 생존율 확인

In [29]:
train_df["AgeBand"] = pd.cut(train_df["Age"], 5) # 훈련 자료의 연령을 5 범주로 나눔
train_df[["AgeBand", "Survived"]].groupby(["AgeBand"], as_index = False).mean().sort_values(by = "AgeBand", ascending = True)
Out[29]:
 AgeBandSurvived
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
 
  • ( ): 포함 안 함(미만, 초과)
  • [ ]: 포함(이하, 이상)
  • 16세 이하 승객의 생존율이 55%로 가장 높고, 64세 초과 승객의 생존율이 약 9%로 나타남
 

연령대를 자료에 추가하고 숫자로 변환

In [30]:
train_df["AgeBand"] = pd.cut(train_df["Age"], bins = 5, labels = [0, 1, 2, 3, 4])

test_df.loc[                        (test_df["Age"] <= 16), "AgeBand"] = 0
test_df.loc[(test_df["Age"] > 16) & (test_df["Age"] <= 32), "AgeBand"] = 1
test_df.loc[(test_df["Age"] > 32) & (test_df["Age"] <= 48), "AgeBand"] = 2
test_df.loc[(test_df["Age"] > 48) & (test_df["Age"] <= 64), "AgeBand"] = 3
test_df.loc[(test_df["Age"] > 64)                         , "AgeBand"] = 4
# 훈련 자료 기준으로 연령대를 나눔

test_df
Out[30]:
 PassengerIdPclassSexAgeSibSpParchFareEmbarkedTitleAgeBand
08923034007.8292Q7.02.0
18933147107.0000S2.02.0
28942062009.6875Q7.03.0
38953027008.6625S7.01.0
489631221112.2875S2.01.0
.................................
41313053025008.0500S7.01.0
4141306113900108.9000C0.02.0
41513073038007.2500S7.02.0
41613083025008.0500S7.01.0
417130930251122.3583C4.01.0

418 rows × 10 columns

 

승선한 가족 규모를 자료에 추가 & 승선한 가족 규모에 따른 생존율

In [31]:
train_df["FamilySize"] = train_df["SibSp"] + train_df["Parch"] + 1 # 1: 자기 자신
test_df[ "FamilySize"] =  test_df["SibSp"] +  test_df["Parch"] + 1

train_df[["FamilySize", "Survived"]].groupby(["FamilySize"], as_index = False).mean().sort_values(by = "FamilySize")
Out[31]:
 FamilySizeSurvived
010.303538
120.552795
230.578431
340.724138
450.200000
560.136364
670.333333
780.000000
8110.000000
 

혼자 여부를 자료에 추가 & 혼자 여부에 따른 생존율

In [32]:
train_df["IsAlone"] = 0
train_df.loc[train_df["FamilySize"] == 1, "IsAlone"] = 1

test_df["IsAlone"] = 0
test_df.loc[test_df["FamilySize"] == 1, "IsAlone"] = 1

train_df[["IsAlone", "Survived"]].groupby(["IsAlone"], as_index = False).mean()
Out[32]:
 IsAloneSurvived
000.505650
110.303538
 

인공 변수 추가

In [33]:
train_df["Age*Class"] = train_df["Age"] * train_df["Pclass"]
test_df[ "Age*Class"] =  test_df["Age"] *  test_df["Pclass"]

train_df.loc[:, ["Age*Class", "Age", "Pclass"]].head(10)
Out[33]:
 Age*ClassAgePclass
066223
138381
278263
335351
4105353
575253
654541
7623
881273
928142
 

승선지 결측 보완

  • 방법: 가장 빈번하게 확인되는 승선지로 보완
 

가장 빈번한 승선지 확인

In [34]:
freq_port = train_df["Embarked"].dropna().mode()[0]

freq_port
Out[34]:
'S'
 

승선지 결측 채우기 & 승선지에 따른 생존율

In [35]:
train_df["Embarked"] = train_df["Embarked"].fillna(freq_port)
test_df[ "Embarked"] =  test_df["Embarked"].fillna(freq_port)

train_df[["Embarked", "Survived"]].groupby(["Embarked"], as_index = False).mean().sort_values(by = "Survived", ascending = False)
Out[35]:
 EmbarkedSurvived
0C0.553571
1Q0.389610
2S0.339009
 

승선지 문자를 숫자로 변환

In [36]:
embarked_mapping = {"S": 0, "C": 1, "Q": 2}

train_df["Embarked"] = train_df["Embarked"].map(embarked_mapping).astype(int)
test_df[ "Embarked"] =  test_df["Embarked"].map(embarked_mapping).astype(int)

train_df.head()
Out[36]:
 SurvivedPclassSexAgeSibSpParchFareEmbarkedTitleAgeBandFamilySizeIsAloneAge*Class
003022107.25000712066
1111381071.28331222038
213126007.92500311178
3111351053.10000222035
403035008.050007211105
 

테스트 자료의 요금 변수 결측 보완

  • 방법: 훈련 자료의 중앙값으로 보완
In [37]:
test_df.info()
 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 13 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  418 non-null    int64  
 1   Pclass       418 non-null    int64  
 2   Sex          418 non-null    int32  
 3   Age          418 non-null    int32  
 4   SibSp        418 non-null    int64  
 5   Parch        418 non-null    int64  
 6   Fare         417 non-null    float64
 7   Embarked     418 non-null    int32  
 8   Title        418 non-null    float64
 9   AgeBand      418 non-null    float64
 10  FamilySize   418 non-null    int64  
 11  IsAlone      418 non-null    int64  
 12  Age*Class    418 non-null    int64  
dtypes: float64(3), int32(3), int64(7)
memory usage: 37.7 KB
In [38]:
test_df["Fare"].fillna(train_df["Fare"].dropna().median(), inplace = True)

test_df.info()
 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 13 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  418 non-null    int64  
 1   Pclass       418 non-null    int64  
 2   Sex          418 non-null    int32  
 3   Age          418 non-null    int32  
 4   SibSp        418 non-null    int64  
 5   Parch        418 non-null    int64  
 6   Fare         418 non-null    float64
 7   Embarked     418 non-null    int32  
 8   Title        418 non-null    float64
 9   AgeBand      418 non-null    float64
 10  FamilySize   418 non-null    int64  
 11  IsAlone      418 non-null    int64  
 12  Age*Class    418 non-null    int64  
dtypes: float64(3), int32(3), int64(7)
memory usage: 37.7 KB
 

요금대에 따른 생존율

In [39]:
train_df["FareBand"] = pd.qcut(train_df["Fare"], q = 4) # 동일한 개수로 나눠서 4 개의 요금 범주 생성
train_df[["FareBand", "Survived"]].groupby(["FareBand"], as_index = False).mean().sort_values(by = "FareBand", ascending = True)
Out[39]:
 FareBandSurvived
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
 
  • 요금대가 비쌀수록 생존율이 높아짐
 

자료에 요금대 변수 추가 & 숫자로 변환

In [40]:
train_df["FareBand"] = pd.qcut(train_df["Fare"], q = 4, labels = [0, 1, 2, 3])

test_df.loc[                             (test_df["Fare"] <=   7.91), "FareBand"] = 0
test_df.loc[(test_df["Fare"] >   7.91) & (test_df["Fare"] <= 14.454), "FareBand"] = 1
test_df.loc[(test_df["Fare"] > 14.454) & (test_df["Fare"] <= 31.0  ), "FareBand"] = 2
test_df.loc[(test_df["Fare"] > 31.0  )                              , "FareBand"] = 3

train_df.head(10)
Out[40]:
 SurvivedPclassSexAgeSibSpParchFareEmbarkedTitleAgeBandFamilySizeIsAloneAge*ClassFareBand
003022107.250007120660
1111381071.283312220383
213126007.925003111781
3111351053.100002220353
403035008.0500072111051
503025008.458327111751
6010540051.862507311543
703023121.07500405062
8131270211.133302130811
9121141030.070812020282
In [41]:
test_df.head(10)
Out[41]:
 PassengerIdPclassSexAgeSibSpParchFareEmbarkedTitleAgeBandFamilySizeIsAloneAge*ClassFareBand
08923034007.829227.02.0111020.0
18933147107.000002.02.0201410.0
28942062009.687527.03.0111241.0
38953027008.662507.01.011811.0
489631221112.287502.01.030661.0
58973014009.225007.00.011421.0
68983130007.629223.01.011900.0
789920261129.000007.01.030522.0
89003118007.229212.01.011540.0
990130212024.150007.01.030632.0
반응형

'인공지능 > 머신러닝' 카테고리의 다른 글

텐서플로우(Tensorflow) 자동 미분과 사용자정의 훈련  (0) 2021.03.07
간단한 자연어 처리 모델  (0) 2020.10.07
Kaggle TMDB  (0) 2020.08.04