감상 :
지난주 강의에 이어서 그나마 빅데이터 분석가 과정에서 배웠던 것을 다시 복습하는 시간이어서 좀 수월한 편이었다.
내가 원하는 분석을 하기 위해 지난주에 배운 numpy, pandas, matplotlib을 어떻게 활용할 수 있을지 생각해 내고, 바로 적용하는 것이 쉽지는 않아서, 예전 수업 자료 노트를 꺼내 정리하면서, 복습했다.
+ 추가 감상:
이후에 주말 특강 과제로 이 titanic 데이터로 kaggle competition에 submit 하는 미션을 했다.
타이타닉 데이터로 EDA 실습은 해본 적 있지만, 직접 생존율 예측 모델을 만들어서 결과를 submit한 적은 없었기 때문에 단시간 내에 결과를 내서 제출해보라고 하니까 허둥대게 되었다.
기존에 다른 사람들이 공개한 노트북 중에서 내가 해본 적 있으면서, 아주 어렵지 않고, 결과물이 잘 나왔던 Randomforestclassifier를 적용한 노트북을 카피한 다음, 내가 잘 모르는 건 빼고 모델을 돌려서 결과물을 냈더니 0.77 정도의 점수가 나왔다.
그다지 높지는 않은 점수로, 변수 처리에서 부족함이 있었는지, 하이퍼 파라미터 튜닝 쪽에서 조정이 필요한지 시간이 더 있을 때 살펴볼 수 있으면 좋겠다.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
# 동일 경로에 "train.csv"가 있다면: #데이터 불러오기 titanic_df = pd.read_csv("titanic.csv")
1. 분석의 목적과 변수 확인
- 타이타닉 호에서 생존한 생존자들은 어떤 사람들인가?
titanic_df.head(5)
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 |
# 각 column의 데이터 타입 확인하기
titanic_df.dtypes
PassengerId int64
Survived int64
Pclass int64
Name object
Sex object
Age float64
SibSp int64
Parch int64
Ticket object
Fare float64
Cabin object
Embarked object
dtype: object
2. 데이터 전체적으로 살펴보기
# 데이터 전체 정보를 얻는 함수 : .describe()
titanic_df.describe() # 수치형 데이터에 대한 요약만을 제공
PassengerId | Survived | Pclass | Age | SibSp | Parch | Fare | |
---|---|---|---|---|---|---|---|
count | 891.000000 | 891.000000 | 891.000000 | 714.000000 | 891.000000 | 891.000000 | 891.000000 |
mean | 446.000000 | 0.383838 | 2.308642 | 29.699118 | 0.523008 | 0.381594 | 32.204208 |
std | 257.353842 | 0.486592 | 0.836071 | 14.526497 | 1.102743 | 0.806057 | 49.693429 |
min | 1.000000 | 0.000000 | 1.000000 | 0.420000 | 0.000000 | 0.000000 | 0.000000 |
25% | 223.500000 | 0.000000 | 2.000000 | 20.125000 | 0.000000 | 0.000000 | 7.910400 |
50% | 446.000000 | 0.000000 | 3.000000 | 28.000000 | 0.000000 | 0.000000 | 14.454200 |
75% | 668.500000 | 1.000000 | 3.000000 | 38.000000 | 1.000000 | 0.000000 | 31.000000 |
max | 891.000000 | 1.000000 | 3.000000 | 80.000000 | 8.000000 | 6.000000 | 512.329200 |
# 상관계수 확인
titanic_df.corr()
# Correlation is NOT Causation
# 상관성 : A up, B up...
# 인과성: A -> B
PassengerId | Survived | Pclass | Age | SibSp | Parch | Fare | |
---|---|---|---|---|---|---|---|
PassengerId | 1.000000 | -0.005007 | -0.035144 | 0.036847 | -0.057527 | -0.001652 | 0.012658 |
Survived | -0.005007 | 1.000000 | -0.338481 | -0.077221 | -0.035322 | 0.081629 | 0.257307 |
Pclass | -0.035144 | -0.338481 | 1.000000 | -0.369226 | 0.083081 | 0.018443 | -0.549500 |
Age | 0.036847 | -0.077221 | -0.369226 | 1.000000 | -0.308247 | -0.189119 | 0.096067 |
SibSp | -0.057527 | -0.035322 | 0.083081 | -0.308247 | 1.000000 | 0.414838 | 0.159651 |
Parch | -0.001652 | 0.081629 | 0.018443 | -0.189119 | 0.414838 | 1.000000 | 0.216225 |
Fare | 0.012658 | 0.257307 | -0.549500 | 0.096067 | 0.159651 | 0.216225 | 1.000000 |
# 결측치 확인
titanic_df.isnull()
PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | False | False | False | False | False | False | False | False | False | False | True | False |
1 | False | False | False | False | False | False | False | False | False | False | False | False |
2 | False | False | False | False | False | False | False | False | False | False | True | False |
3 | False | False | False | False | False | False | False | False | False | False | False | False |
4 | False | False | False | False | False | False | False | False | False | False | True | False |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
886 | False | False | False | False | False | False | False | False | False | False | True | False |
887 | False | False | False | False | False | False | False | False | False | False | False | False |
888 | False | False | False | False | False | True | False | False | False | False | True | False |
889 | False | False | False | False | False | False | False | False | False | False | False | False |
890 | False | False | False | False | False | False | False | False | False | False | True | False |
891 rows × 12 columns
titanic_df.isnull().sum()
#Age, Cabin, Embarked 에서 결측치 발견!
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
3. 데이터의 개별 속성 파악하기
1. Survived Column
# 생존자, 사망자 명수는?
titanic_df['Survived'].sum() #.value_counts()써도 됨
342
# 생존자 수와 사망자 수를 barplot으로 그려보기 sns.countplot()
sns.countplot(x = 'Survived', data=titanic_df)
plt.show()
2. Pclass
# pclass에 따른 인원 파악
titanic_df[['Pclass','Survived']]
Pclass | Survived | |
---|---|---|
0 | 3 | 0 |
1 | 1 | 1 |
2 | 3 | 1 |
3 | 1 | 1 |
4 | 3 | 0 |
... | ... | ... |
886 | 2 | 0 |
887 | 1 | 1 |
888 | 3 | 0 |
889 | 1 | 1 |
890 | 3 | 0 |
891 rows × 2 columns
titanic_df[['Pclass','Survived']].groupby(['Pclass']).count()
# 각 클래스에 해당하는 인원을 보여줌
Survived | |
---|---|
Pclass | |
1 | 216 |
2 | 184 |
3 | 491 |
#생존자만 보여줌
titanic_df[['Pclass', 'Survived']].groupby(['Pclass']).sum()
Survived | |
---|---|
Pclass | |
1 | 136 |
2 | 87 |
3 | 119 |
#생존 비율
titanic_df[['Pclass', 'Survived']].groupby(['Pclass']).mean()
Survived | |
---|---|
Pclass | |
1 | 0.629630 |
2 | 0.472826 |
3 | 0.242363 |
# 히트맵을 활용해 생존율을 보다 직관적으로 보여주기
sns.heatmap(titanic_df[['Pclass', 'Survived']].groupby(['Pclass']).mean())
plt.plot()
3. Sex
titanic_df.groupby(['Survived','Sex']).count()
PassengerId | Pclass | Name | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | ||
---|---|---|---|---|---|---|---|---|---|---|---|
Survived | Sex | ||||||||||
0 | female | 81 | 81 | 81 | 64 | 81 | 81 | 81 | 81 | 6 | 81 |
male | 468 | 468 | 468 | 360 | 468 | 468 | 468 | 468 | 62 | 468 | |
1 | female | 233 | 233 | 233 | 197 | 233 | 233 | 233 | 233 | 91 | 231 |
male | 109 | 109 | 109 | 93 | 109 | 109 | 109 | 109 | 45 | 109 |
#각 컬럼만 지정해서 카운트를 할 수 있다.
titanic_df.groupby(['Survived','Sex'])['Survived'].count()
Survived Sex
0 female 81
male 468
1 female 233
male 109
Name: Survived, dtype: int64
sns.catplot(x='Sex', col = 'Survived', kind = 'count', data=titanic_df)
<seaborn.axisgrid.FacetGrid at 0x11c659c70>
4. Age
-결측치의 존재를 잊지 말 것
titanic_df.describe()['Age']
count 714.000000
mean 29.699118
std 14.526497
min 0.420000
25% 20.125000
50% 28.000000
75% 38.000000
max 80.000000
Name: Age, dtype: float64
#survived와 Age의 경향성
#fig -> axis -> plot
titanic_df[titanic_df.Survived ==1]['Age']
1 38.0
2 26.0
3 35.0
8 27.0
9 14.0
...
875 15.0
879 56.0
880 25.0
887 19.0
889 26.0
Name: Age, Length: 342, dtype: float64
fig, ax = plt.subplots(1, 1, figsize =(10,5))
sns.kdeplot(x=titanic_df[titanic_df.Survived ==1]['Age'],ax=ax)
sns.kdeplot(x=titanic_df[titanic_df.Survived ==0]['Age'],ax=ax)
plt.legend(['Survived','Dead'])
plt.show()
APPENDIX 1. Sex+Pclass vs. Survived
sns.catplot(x = 'Pclass', y = 'Survived', hue = 'Sex', kind = 'point', data = titanic_df)
plt.show()
APPENDIX 2. Age+Pclass
# Age graph with Pclass
titanic_df['Age'][titanic_df.Pclass == 1]
1 38.0
3 35.0
6 54.0
11 58.0
23 28.0
...
871 47.0
872 33.0
879 56.0
887 19.0
889 26.0
Name: Age, Length: 216, dtype: float64
titanic_df[['Parch','Survived']].groupby(['Parch']).count()
Survived | |
---|---|
Parch | |
0 | 678 |
1 | 118 |
2 | 80 |
3 | 5 |
4 | 4 |
5 | 5 |
6 | 1 |
titanic_df[['Parch','Survived']].groupby(['Parch']).mean()
Survived | |
---|---|
Parch | |
0 | 0.343658 |
1 | 0.550847 |
2 | 0.500000 |
3 | 0.600000 |
4 | 0.000000 |
5 | 0.200000 |
6 | 0.000000 |
fig, ax = plt.subplots(1, 1, figsize =(10,5))
sns.kdeplot(x=titanic_df[titanic_df.Survived ==1]['Parch'],ax=ax)
sns.kdeplot(x=titanic_df[titanic_df.Survived ==0]['Parch'],ax=ax)
plt.legend(['Survived','Dead'])
plt.show()
fig, ax = plt.subplots(1, 1, figsize =(10,5))
sns.kdeplot(x=titanic_df[titanic_df.Survived ==1]['Fare'],ax=ax)
sns.kdeplot(x=titanic_df[titanic_df.Survived ==0]['Fare'],ax=ax)
plt.legend(['Survived','Dead'])
plt.show()
plt.hist(x = 'Parch', data = titanic_df)
plt.show()
titanic_df[['SibSp','Survived']].groupby(['SibSp']).count()
Survived | |
---|---|
SibSp | |
0 | 608 |
1 | 209 |
2 | 28 |
3 | 16 |
4 | 18 |
5 | 5 |
8 | 7 |
titanic_df[['SibSp','Survived']].groupby(['SibSp']).mean()
Survived | |
---|---|
SibSp | |
0 | 0.345395 |
1 | 0.535885 |
2 | 0.464286 |
3 | 0.250000 |
4 | 0.166667 |
5 | 0.000000 |
8 | 0.000000 |
plt.hist(x = 'SibSp', data = titanic_df)
plt.show()
titanic_df.corr()
PassengerId | Survived | Pclass | Age | SibSp | Parch | Fare | |
---|---|---|---|---|---|---|---|
PassengerId | 1.000000 | -0.005007 | -0.035144 | 0.036847 | -0.057527 | -0.001652 | 0.012658 |
Survived | -0.005007 | 1.000000 | -0.338481 | -0.077221 | -0.035322 | 0.081629 | 0.257307 |
Pclass | -0.035144 | -0.338481 | 1.000000 | -0.369226 | 0.083081 | 0.018443 | -0.549500 |
Age | 0.036847 | -0.077221 | -0.369226 | 1.000000 | -0.308247 | -0.189119 | 0.096067 |
SibSp | -0.057527 | -0.035322 | 0.083081 | -0.308247 | 1.000000 | 0.414838 | 0.159651 |
Parch | -0.001652 | 0.081629 | 0.018443 | -0.189119 | 0.414838 | 1.000000 | 0.216225 |
Fare | 0.012658 | 0.257307 | -0.549500 | 0.096067 | 0.159651 | 0.216225 | 1.000000 |
- 'Embarked'변수, 즉, 어떤 항구에서 탑승했느냐가 생존 변수와 유의미한 관련이 있는지 살펴보려고 합니다.
- 먼저 'Embarked' 변수에 따른 빈도를 살펴보려고 합니다.
titanic_df['Embarked'].value_counts()
S 644
C 168
Q 77
Name: Embarked, dtype: int64
sns.countplot(x='Embarked', data = titanic_df)
plt.show()
- 골고루 분산되어 있는 것이 아니라 'S' 항구에서 집중 적으로 탑승했고, 'C'항구, 'Q'항구에서는 상대적으로 덜 탑승한 것을 알 수 있습니다.
- 탑승 항구 별로 생존/ 비생존자의 비율이 다르게 나타날까요?
titanic_df[['Embarked','Survived']].groupby(['Embarked']).mean()
Survived | |
---|---|
Embarked | |
C | 0.553571 |
Q | 0.389610 |
S | 0.336957 |
- 'C' 항구에서 탑승한사람 중에서는 0.5가 넘어서 사망자보다 생존자가 더 많았던 반면에,
- 가장 많은 사람이 탑승했던 'S' 항구에서는 안타깝게도 사망자의 비율이 더 높았던 것으로 확인됩니다.
sns.countplot(x = 'Embarked', hue = 'Survived', data = titanic_df)
plt.show()
- 왜 특정 항구에서 탑승한 사람들의 사망률이 더 높을까요? 모두가 탑승하고 있다가 동시에 침몰 사고를 당했는데 말이죠.
혹시 각 항구에 탑승한 사람들 사이에 경제적 차이가 있었던 것은 아닐까요? 우리는 이미 비싼 1등석 탑승자들이 생존율이 높았던 것을 알고 있습니다.
sns.countplot(x = 'Embarked', hue = 'Pclass', data = titanic_df)
plt.show()
- 역시나 사망률이 높은 'S'항구 탑승자들 사이에서는 3등석 구매자들이 월등히 높고,
- 상대적으로 생존율이 높았던 'C'항구 탑승자들 중에는 '1등석' 탑승자가 50%는 되어 보이는 군요.
sns.catplot(x='Embarked', col = 'Survived', hue = 'Pclass' , kind = 'count', data=titanic_df)
plt.show()
- 사망자와 생존자를 나눠서 살펴보았더니, 역시 사망자 쪽에서 3등석 탑승자의 수가 더 많고, 생존자들은 상대적으로 '1등석 탑승자'의 비율이 높은 것 같습니다.
- EDA로 한눈에 보았을 때는 항구 별 몇 등석 탑승자이냐의 비율이 다르기 때문에 이렇게 탑승 항구별로 생존율의 차이가 난 것 같군요. 물론 몇 등석에 탑승했는지의 영향을 배제하고도 어떤 항구에서 탑승했냐가 생존율의 차이에 영향을 미쳤는지는 보다 깊이 있는 분석을 해야 알 수 있겠지만요.
'Data > EDA' 카테고리의 다른 글
kaggle 시작은 필사부터 - notebook grandmaster subinium님 자료 (0) | 2021.05.21 |
---|---|
[AI class day13] 파이썬 매트플롯, 씨본 python matplotlib, seaborn TIL (0) | 2021.05.07 |