Data/EDA

[AI Class Day 16, 17] EDA TIL

makeitworth 2021. 5. 13. 17:59

감상 :

지난주 강의에 이어서 그나마 빅데이터 분석가 과정에서 배웠던 것을 다시 복습하는 시간이어서 좀 수월한 편이었다.

내가 원하는 분석을 하기 위해 지난주에 배운 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로 한눈에 보았을 때는 항구 별 몇 등석 탑승자이냐의 비율이 다르기 때문에 이렇게 탑승 항구별로 생존율의 차이가 난 것 같군요. 물론 몇 등석에 탑승했는지의 영향을 배제하고도 어떤 항구에서 탑승했냐가 생존율의 차이에 영향을 미쳤는지는 보다 깊이 있는 분석을 해야 알 수 있겠지만요.