Kaggle 캐글 : 타이타닉으로 입문하기(1) - 데이터 탐색 & 전처리
1) Titanic 데이터 탐색
1. 기본정보
PassengerId : 승객 ID
Survived: 0은 죽었다는 의미, 1은 생존의 의미
Pclass : 좌석 등급
Name : 승객 이름
Age : 승객 나이
SibSp: 함께 탑승한 형제 자매 또는 배우자의 수
Parch: 함께 탑승한 부모, 아이의 수
Ticket : 티켓 번호
Fare : 티켓 가격
Cabin: 객실 번호
Embarked : 탑승 항구
train=pd.read_csv('/kaggle/input/titanic/train.csv')
test=pd.read_csv('/kaggle/input/titanic/test.csv')
train.head()
test.head()
## test.csv 에는 survived 칼럼이 없다. 왜냐하면 종속변수이기 때문이다.(예측해야 함)
train.info()
## 총 891개가 있어야 결측값(NaN)이 없는 것이다. 그러나 Age, Cabin, Embarked는 결측값을 가진다.
train.isnull().sum() ## 결측값만 표시하는 방법이다.
test.isnull().sum()
2. 결측치는 데이터를 채울 것인지 버릴 것인지 결정해야한다.
3. 이 과정에서는 필요한 데이터가 무엇인지를 고려해야한다. 필요없는 데이터는 나중에 제거를 할 수 있습니다.
또, 문자열은 숫자로 바꿔야 합니다.
2) 데이터 전처리
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
## 캐글 노트북을 사용하는 경우에는 다음처럼 매직(magic) 명령으로 노트북 내부에 그림을 표시하도록 지정해야 한다.
import seaborn as sns
sns.set()
## 그래프 기본스타일 설정
1. Name
- 이름은 생존과 관련이 없을 수도 있지만, Mr,Mrs 등 결혼의 유무를 알 수 있는
타이틀은 고려할 사항이 될 수 있습니다.
- 타이틀만 추출하여 Name칼럼은 삭제한다.
train_test_data=[train,test]
## train과 test 데이터셋 합침
train_test_data
for dataset in train_test_data:
dataset['Title']=dataset['Name'].str.extract('([A-Za-z]+)\.',expand=False)
## '([A-Za-z]+)\.' :정규표현식
## 대문자 A-Z로 시작하면서 소문자 a-z가 여러개이면서 마침표 .로 끝나는 것을 추출한다는 의미이다.
## 예로, Braund, Mr. Owen Harris 에서 Mr 를 추출한다는 말
train['Title'].value_counts()
test['Title'].value_counts()
1-1. Mr, Miss, Mrs, Master를 제외한 나머지들은 그 수가 너무 적은 것을 알 수 있습니다.
사전적 의미를 따져보면,
Mile, Ms -> Miss
Mme, Lady, Countness, Dona -> Mrs
Major, Col, Sir, Don, Jockheer, Capt -> Mr 로 변경할 수 있습니다.
1-2. 남은 Dr, Rev, Master는 성별을 추측하기 힘드므로 트레이닝 데이터를 확인해봅니다.
train[train['Title']=='Dr']['Sex']
train[train['Title']=='Rev']['Sex']
train[train['Title']=='Master']['Sex']
1-3. Dr 1명 빼곤 모두 male 이므로 저는 셋 다 Mr로 변경하기로 했습니다.
1-4. Mr ->0, Miss ->1, Mrs -> 2 로 매핑합니다.
title_mapping={
'Don':0,
'Rev':0,
'Capt':0,
'Jonkheer':0,
'Mr':0,
'Dr':0,
'Major':0,
'Col':0,
'Master':0,
'Sir':0,
'Miss':1,
'Mlle':1,
'Ms':1,
'Mrs':2,
'Mme':2,
'Lady':2,
'Countess':2
}
for dataset in train_test_data:
dataset['Title']=dataset['Title'].map(title_mapping)
2. Sex
sex_mapping={'male':0,'female':1}
for dataset in train_test_data:
dataset['Sex']=dataset['Sex'].map(sex_mapping)
2-1. Sex는 남자면 0 여자면 1로 매핑을 했습니다.
3. Age
facet=sns.FacetGrid(train,hue="Survived",aspect=3)
facet.map(sns.kdeplot,'Age',shade=True)
facet.set(xlim=(0,train['Age'].max()))
facet.add_legend()
3-1. Age는 177개의 결측치가 있었으므로 데이터를 채울지 버릴지 결정해야합니다.
위 그래프를 보시면 0살에서 약 16살까지는 생존할 확률이 더 높은것을 알 수 있습니다.
반면 20대 중반에서 30대 초반까지는 죽을 확률이 더 높은 것을 알 수 있습니다.
Age가 생존에 여부를 판단하는데 꽤 중요한 변수가 될 것 같습니다.
그리고 그렇기 때문에 결측치를 채워야 할 것 같습니다.
3-2. NAN은 Tilte의 median으로 채울 것입니다.
모두 Mr, Miss, Mrs로 변경하기 전 Title을 이용할 것입니다.
for dataset in train_test_data:
dataset['Title2']=dataset['Name'].str.extract('([A-Za-z]+)\.',expand=False)
fill=train.groupby('Title2')['Age'].transform('median')
train['Age'].fillna(fill,inplace=True)
## Title의 median으로 결측값 채우기
train.isnull().sum()
## 결측값이 사라졌는지 확인
3-3. 결측값을 채웠으니, Age를 10~60를 5단위로 나누었습니다.
for dataset in train_test_data:
dataset.loc[ dataset['Age']<=10, 'Age'] = 0,
dataset.loc[(dataset['Age']>10)&(dataset['Age']<=16), 'Age'] = 1,
dataset.loc[(dataset['Age']>16)&(dataset['Age']<=20), 'Age'] = 2,
dataset.loc[(dataset['Age']>20)&(dataset['Age']<=26), 'Age'] = 3,
dataset.loc[(dataset['Age']>26)&(dataset['Age']<=30), 'Age'] = 4,
dataset.loc[(dataset['Age']>30)&(dataset['Age']<=36), 'Age'] = 5,
dataset.loc[(dataset['Age']>36)&(dataset['Age']<=40), 'Age'] = 6,
dataset.loc[(dataset['Age']>40)&(dataset['Age']<=46), 'Age'] = 7,
dataset.loc[(dataset['Age']>46)&(dataset['Age']<=50), 'Age'] = 8,
dataset.loc[(dataset['Age']>50)&(dataset['Age']<=60), 'Age'] = 9,
dataset.loc[ dataset['Age']>60, 'Age'] = 10
4. Embarked
4-1. Embarked 에서 결측치를 가진 행을 추출했습니다.
train[train['Embarked'].isnull()==True]
4-2. 두 사람 모두 SibSp, Parch를 봤을 때 동승자가 없으므로 추측하기 힘들어 가장 빈도수가 높은 값을 넣겠습니다.
train['Embarked'].value_counts()
4-3. S가 가장 많으므로 S로 매핑한 후, 생존율을 확인합니다.문자열을 숫자로 바꾸기 위해 S->0, C->1, Q->2 로 한번 더 매핑하겠습니다.
train['Embarked'].fillna('S',inplace=True)
fig = plt.figure(figsize=(15,6))
i=1
for x in train['Embarked'].unique():
fig.add_subplot(3, 6, i)
plt.title('Em : {}'.format(x))
train.Survived[train['Embarked'] == x].value_counts().plot(kind='pie')
i += 1
4-4. 생존율이 낮은 순으로 매핑하겠습니다.
embarked_mapping={
'S':0,'Q':1,'C':2
}
for dataset in train_test_data:
dataset['Embarked']=dataset['Embarked'].map(embarked_mapping)
5. SibSp & Parch
5-1. SibSp 와 Parch의 합이 높을 수록 부양가족이 많다는 것을 의미하므로 두개의 합에 따른 생존율을 보겠습니다.
fig = plt.figure(figsize=(15,6))
i=1
for size in train['Family'].unique():
fig.add_subplot(3, 6, i)
plt.title('Size : {}'.format(size))
train.Survived[train['Family'] == size].value_counts().plot(kind='pie')
i += 1
5-2. 생존율이 낮은 순으로 매핑하겠습니다.
family_mapping = {
1: 3,
2: 5,
3: 6,
4: 7,
5: 2,
6: 1,
7: 4,
8: 0,
11: 0
}
for dataset in train_test_data:
dataset['Family']=dataset['Family'].map(family_mapping)
6. Cabin & Fare
6-1. Cabin의 앞글자만 따오기로 합니다.
for dataset in train_test_data:
dataset['Cabin']=dataset['Cabin'].str[:1]
6-2. 결측값에는 'N'을 넣어줍니다.(그냥 NaN값을 의미함)
train['Cabin'].fillna('N', inplace=True)
test['Cabin'].fillna('N', inplace=True)
6-3. test의 Fare값의 결측치에는 Cabin의 median으로 채운 후 test의 결측치를 확인한다.
fill=train.groupby('Cabin')['Fare'].transform('median')
test['Fare'].fillna(fill,inplace=True)
test.isnull().sum()
6-4. Fare 값이 너무 다양하여 범위를 나눠준다.
for dataset in train_test_data:
dataset.loc[ dataset['Fare']<=30, 'Fare'] = 0,
dataset.loc[(dataset['Fare']>30)&(dataset['Fare']<=80), 'Fare'] = 1,
dataset.loc[(dataset['Fare']>80)&(dataset['Fare']<=100), 'Fare'] = 2,
dataset.loc[(dataset['Fare']>100), 'Fare'] = 3
6-5. 아까 Cabin의 값을 'N'으로 넣어준 사람들에게 존재하는 Cabin값으로 넣어주기 위해 각 Cabin별로 어떤 Fare범위가 가장 많은지 확인하고 해당 값으로 'N'값을 대체한다.
fig = plt.figure(figsize=(15,6))
i=1
for x in train['Cabin'].unique():
fig.add_subplot(3, 6, i)
plt.title('Cabin : {}'.format(x))
train.Fare[train['Cabin'] == x].value_counts().plot(kind='pie')
i += 1
for dataset in train_test_data:
dataset.loc[(dataset['Cabin'] == 'N')&(dataset['Fare'] == 0), 'Cabin'] = 'G',
dataset.loc[(dataset['Cabin'] == 'N')&(dataset['Fare'] == 1), 'Cabin'] = 'T',
dataset.loc[(dataset['Cabin'] == 'N')&(dataset['Fare'] == 2), 'Cabin'] = 'C',
dataset.loc[(dataset['Cabin'] == 'N')&(dataset['Fare'] == 3), 'Cabin'] = 'B',
6-6. Cabin에 따른 생존률을 비교하여 낮은 순으로 매핑합니다.
fig = plt.figure(figsize=(15,6))
i=1
for x in train['Cabin'].unique():
fig.add_subplot(3, 6, i)
plt.title('Cabin : {}'.format(x))
train.Survived[train['Cabin'] == x].value_counts().plot(kind='pie')
i += 1
for dataset in train_test_data:
dataset.loc[(dataset['Cabin'] == 'G'), 'Cabin'] = 0,
dataset.loc[(dataset['Cabin'] == 'C'), 'Cabin'] = 3,
dataset.loc[(dataset['Cabin'] == 'E'), 'Cabin'] = 5,
dataset.loc[(dataset['Cabin'] == 'T'), 'Cabin'] = 1,
dataset.loc[(dataset['Cabin'] == 'D'), 'Cabin'] = 7,
dataset.loc[(dataset['Cabin'] == 'A'), 'Cabin'] = 2,
dataset.loc[(dataset['Cabin'] == 'B'), 'Cabin'] = 6,
dataset.loc[(dataset['Cabin'] == 'F'), 'Cabin'] = 4
6-7. Fare에 따른 생존율을 비교하여 낮은 순으로 매핑합니다.
fig = plt.figure(figsize=(15,6))
i=1
for x in train['Fare'].unique():
fig.add_subplot(3, 6, i)
plt.title('Fare : {}'.format(x))
train.Survived[train['Fare'] == x].value_counts().plot(kind='pie')
i += 1
for dataset in train_test_data:
dataset.loc[(dataset['Fare'] == 0), 'Fare'] = 0,
dataset.loc[(dataset['Fare'] == 1), 'Fare'] = 1,
dataset.loc[(dataset['Fare'] == 2), 'Fare'] = 3,
dataset.loc[(dataset['Fare'] == 3), 'Fare'] = 2
7. Pclass
7-1. Pclass에 따른 생존율을 비교하여 낮은 순으로 매핑합니다.
fig = plt.figure(figsize=(15,6))
i=1
for x in train['Pclass'].unique():
fig.add_subplot(3, 6, i)
plt.title('Pclass : {}'.format(x))
train.Survived[train['Pclass'] == x].value_counts().plot(kind='pie')
i += 1
for dataset in train_test_data:
dataset.loc[dataset['Pclass']==3,'Pclass'] = 0
dataset.loc[dataset['Pclass']==2,'Pclass'] = 1
dataset.loc[dataset['Pclass']==1,'Pclass'] = 2
8. 불필요한 데이터 제거
train.drop(['PassengerId','Name','SibSp','Parch','Title2','Ticket'],axis=1,inplace=True)
test.drop(['Name','SibSp','Parch','Title2','Ticket'],axis=1,inplace=True)