www.kaggle.com/ash316/eda-to-prediction-dietanic
(※ 오늘은 이 캐글러의 공유 코드를 활용해 공부하는 내용입니다.)
타이타닉이 캐글의 튜토리얼이라고는 하나, 나와 같은 초심자에게는 매우 다루기 어려운 데이터다.
여기저기 참고해서 분류를 실행했지만 캐글에서는 순위도 부여받지 못하는 등수에 랭크됐다.
그래서 이번에는 상위 4%에 해당하는 결과를 도출한 캐글러의 코드를 이용해
- 어떤 과정을 거쳐 분석했는지
- 어떤 플롯으로 사용했는지
- feature에서 어떻게 인사이트를 도출했는지
- 어떤 과정으로 그런 인사이트를 도출했는지
- 캐글러는 어떤 수준의 코드를 만드는지
종합적으로 다루어 EDA부터 모델링과 분류, 예측하는 방법을 발전시키고자 한다.
이 캐글러는 아래와 같은 과정으로 진행했다.
1장. EDA
1) feature 분석
2) 여러 feature들간의 관계, 경향 찾기
2장. Feature Engineering and Data Cleaning
1) 새로운 Feature 추가
2) 반복되는 feature 제거
3) 모델링에 적합한 형태로 feature 변환
3장. Predictive Modeling
1) 기본적인 알고리즘 실행
2) CrossValidation(교차 검증)
3) Ensembling(앙상블 기법)
4) 중요한 특성 추출(Important Feature Extraction)
자, 그럼 EDA부터 따라해보자!
1장. EDA
1) feature 분석
#라이브러리
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('fivethirtyeight')
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
이 캐글러는 기본적으로 위 라이브러리를 활용해 EDA를 진행했다.
#데이터 불러오기
data = pd.read_csv('../train.csv')
라이브러리를 불러오고 데이터를 불러왔다.
여기서 한 가지 참고할 점은, 아직 train, test를 만들지 않아서인지 이 분은 data로 train.csv 파일을 불러왔다.
나중에 전처리하고 train데이터를 만들었을 때 변수 이름이 겹쳐 발생할 수 있는 불상사를 방지하기 위해 data라고 불러온 것 같다.
#결측치 확인
data.isnull().sum()
data 파일의 결측치를 확인하니 Age, Cabin, Embarked 칼럼에 결측이 있었다.
""몇 명이나 살아남았는가?""
이 그래프를 만들기 위해 아래 코드를 사용했다.
#생존 비율 알아보기
f, ax = plt.subplots(1, 2, figsize = (18, 8))
data['Survived'].value_counts().plot.pie(explode = [0, 0.1],
autopct = '%1.1f%%', ax = ax[0], shadow = True)
ax[0].set_title('Survived')
ax[0].set_ylabel('')
sns.countplot('Survived', data = data, ax = ax[1])
ax[1].set_title('Surived')
plt.show()
f, ax = plt.subplots(1, 2, figsize = (18, 8))
-> 그래프를 그릴건데 한번에 1행 2열로 구성(plt.subplot(1, 2))해서 출력할 것이다
그 사이즈는 가로 18, 세로 8 (figsize = (18, 8))
그래프는 f로 출력할 수 있고, ax는 subplot을 코드와 형식을 저장하는 듯 하다. ( f, ax = plt.subplot() )
ax에 코드가 저장되었으므로 ax로 코딩을 한다.
data['Survived'].value_counts().plot.pie(explode = [0, 0.1], autopct = '%1.1f%%', ax = ax[0], shadow = True)
-> data의 Survived 칼럼의 빈도수를 셀건데(data['Survived'].value_counts()) 이를 원 그래프(plot.pie) 로 그려라.
원 그래프 첫번째 옵션으로 explode 옵션은 퍼짐 정도를 나타낸다. 중심에서 첫번째 도수는 0만큼 떨어지고 두번째는 0.1만큼 떨어뜨리는 것이다. (explode = [0, 0.1])
두번째 옵션은 autopct로 도수의 비율을 소수 첫째자리까지 표현한다. (autopct = '%1.1f%%')
세번째 옵션은 원 그래프를 subplot 중 첫째로 출력하라는 것이다. (ax = ax[0])
마지막 옵션은 그래프에 그림자를 그리는 옵션이다. (shadow = True)
----------> 원 그래프를 그릴 때, value_counts()뒤에 .plot.pie() 함수로도 그릴 수 있다는 것과 원 그래프의 옵션 중 explode, subplot의 위치를 지정하는 방법을 처음 배웠다.
ax[0].set_title('Survived')
-> subplot의 첫번째 그래프(ax[0]) 이름을 'Survived'로 지정한다. (.set_title('Survived'))
ax[0].set_ylabel('')
-> subplot의 첫번째 그래프(ax[0])에서 y에 해당하는 레이블 이름을 공백으로 지정한다. (.set_ylabel(''))
sns.countplot('Survived', data = data, ax = ax[1])
-> seaborn 패키지의 countplot으로 막대그래프를 그린다. sns.countplot()
'Survived' 칼럼에 대해서 그리고, 데이터는 data이다. ('Survived', data = data)
subplot중 두번째 열에 그려라 (ax = ax[1])
ax[1].set_title('Survived')
-> subplot의 두번째 그래프(ax[1])도 이름을 'Survived'로 지정한다. (.set_title('Survived'))
plt.show()
-> 그렇게 그린 그래프를 보여다오..
이제 이 그래프에서 간단한 인사이트를 확보하자.
생존자(38.4%)보다 사망자(61.6%)가 훨씬 많았다.
이제 어떤 특성을 가진 사람들이 생존했는지 알아보기 위해 서로 다른 feature로 생존률을 비교해볼 것이다.
그 첫번째 단계로, 서로 다른 feature에 대해 이해해보자.
""Feature의 형태""
명목변수, 순서변수, 연속형 변수에 대해 이해할 필요가 있다.
Titanic 데이터에서 명목변수는 성별('Sex'), 승선장('Embarked'), 순서변수는 등급('Pclass'), 연속변수는 나이('Age')가 있다.
"특성 분석"
- 1) 성별 ('Sex') 특성
data.groupby(['Sex', 'Survived'])['Survived'].count()
.groupby(feature)은 feature 특성을 제외한 데이터프레임의 모든 특성을, feature 특성으로 그룹화한다.
.groupby(feature).count()로 그룹화한 각 feature의 빈도수를 출력한다.
(.gropuby(feature).mean() 등도 가능. 단, mean()이 계산 가능한 feature만 결과가 출력된다.)
.groupby([feature1, feature2]) -> feature1로 묶고 그걸 feature2로 다시 묶어서 그룹화한다.
data.groupby(['Sex', 'Survived'])['Survived'].count()
-> 성별로 한 번(female, male로 그룹화 한 번)
생존으로 두 번 그룹화(Survived = 0, Survived = 1로 그룹화) data.groupby(['Sex', 'Survived'])
그 후 빈도수를 센 결과 중 'Survived' 특성만 출력한다. ['Survived'].count()
f, ax = plt.subplots(1, 2, figsize = (18, 8))
data[['Sex', 'Survived']].groupby(['Sex']).mean().plot.bar(ax = ax[0])
ax[0].set_title('Survived vs Sex')
sns.countplot('Sex', hue = 'Survived', data = data, ax = ax[1])
ax[1].set_title('Sex: Survived vs Dead')
plt.show()
f, ax = plt.subplots(1, 2, figsize = (18, 8))
-> 1행 2열로 구성된 그래프를 그릴거다. 그림은 가로 18, 세로 8
data[['Sex', 'Survived']].groupby(['Sex']).mean().plot.bar(ax = ax[0])
-> data 데이터의 'Sex', 'Survived' 특성만 추려서 (data[['Sex', 'Survived']])
'Sex' 특성으로 그룹화해(female, male로 그룹화) (.groupby(['Sex']))
각 그룹의 평균을 구하는데 (.mean())
막대그래프로 그려서 .plot.bar()
첫번째 그래프로 그려라. (ax = ax[0])
-----------------------> 파이썬에서 .groupby() 함수를 사용하는 것을 다시금 배웠다.
ax[0].set_title('Survived vs Sex')
-> 첫번째 그래프의 타이틀은 'Survived vs Sex'로 지정
sns.countplot('Sex', hue = 'Survived', data = data, ax = ax[1])
-> seaborn 패키지로 막대그래프를 그리는데 (sns.countplot())
'Sex' 특성에 대한 막대그래프를 그리고 sns.countplot('Sex')
'Survived' 특성으로 분류해라. (hue = 'Survived')
데이터는 data다. (data = data)
두번째 그래프에 그려라. (ax = ax[1])
ax[1].set_title('Sex: Survived vs Dead')
-> 두번째 그래프의 타이틀은 'Sex: Survived vs Dead'로 지정
plt.show()
-> 그린 그래프를 보여다오..
여성의 생존률(75%)이 남성(18-19%)보다 매우 높았다.
따라서, 성별은 매우 중요한 피쳐가 될 것으로 보인다.
다른 피쳐도 확인해보자.
- 2) Pclass(등급) 특성 = 순서 변수
이것은 crosstab이라고 불리는 교차표로 빈도를 나타낸다.
진하게 표현된 부분이 높은 비율을, 연하게 표현된 부분은 낮은 비율을 의미한다.
이 crosstab으로 3등석은 높은 비율의 사망률을 보인 점과
1등석은 비교적 높은 비율의 생존률을 보였음을 확인할 수 있다.
pd.crosstab(data.Pclass, data.Survived, margins = True).style.background_gradient(cmap = 'summer_r')
pd.crosstab(data.Pclass, data.Survived, margins = True).style.background_gradient(cmap = 'summer_r')
-> pandas 패키지의 crosstab() 함수를 써서 crosstab을 그릴 것이다. (pd.crosstab())
Pclass랑 Survived 특성으로 교차표를 만들어서 보여다오. (pd.crosstab(data.Pclass, data.Survived)
margin(총합)도 표시해다오. (margins = True) (Default는 margins = False라서 총합 표시가 안된다.)
crosstab을 보기좋게 색칠할 것인데 'summer_r' 테마로 해주렴 ( .style.background_gradient(cmap = 'summer_r') )
summer_r 말고 summer는
f, ax = plt.subplots(1, 2, figsize = (18, 8))
data['Pclass'].value_counts().plot.bar(color = ['#CD7F32', '#FFDF00', '#D3D3D3'], ax = ax[0])
ax[0].set_title('Number Of Passengers By Pclass')
ax[0].set_ylabel('Count')
sns.countplot('Pclass', hue = 'Survived', data = data, ax = ax[1])
ax[1].set_title('Pclass: Survived vs Dead')
plt.show()
f, ax = plt.subplots(1, 2, figsize = (18, 8))
-> 1행 2열로 두 개의 그래프를 그릴 평면을 정한다. 크기는 18*8
data['Pclass'].value_counts().plot.bar(color = ['#CD7F32', '#FFDF00', '#D3D3D3'], ax = ax[0])
-> Pclass 특성의 빈도를 막대그래프로 그려라. (data['Pclass'].value_counts().plot.bar())
막대그래프에서 각 클래스 별 막대의 색깔을 지정해주는 옵션 (color = ['color1', 'color2', 'color3'])
이 막대그래프는 평면에서 첫번째로 그려라 (ax = ax[0])
ax[0].set_title('Number Of Passengers By Pclass')
-> 첫번째 그래프의 타이틀은 'Number Of Passengers By Pclass'로 지정
ax[0].set_ylabel('Count')
-> 첫번째 그래프의 y축 레이블을 'Count'라고 지정
sns.countplot('Pclass', hue = 'Survived', data = data, ax = ax[1])
-> seaborn패키지로 Pclass 특성에 대한 막대그래프를 그려라. (sns.countplot('Pclass'))
근데 이를 'Survived'로 그룹화를 해서 그려라. (hue = 'Survived')
데이터명은 data (data = data)
두번째 그래프로 그려라 (ax = ax[1])
ax[1].set_title('Pclass: Survived vs Dead')
-> 두번째 그래프의 타이틀은 'Pclass: Survived vs Dead'로 지정
plt.show()
-> 이대로 그린 그래프를 보여다오.
3등석에 해당하는 사람은 약 500명으로 가장 많았지만 생존률은 제일 낮았다. (약 25%)
2등석의 생존률은 약 48%
반면 1등석의 생존률은 63%로 3등석에 비해 매우 높았다.
따라서, Pclass와 생존이 중요한 연관성이 있는 것으로 보였다.
이제 성별과 등석을 함께 비교해보자.
pd.crosstab([data.Sex, data.Survived], data.Pclass,
margins = True).style.background_gradient(cmap = 'summer_r')
pd.crosstab([data.Sex, data.Survived], data.Pclass, margins = True).style.background_gradient(cmap = 'summer_r')
-> 교차표를 그린다. (pd.crosstab())
성별과 생존여부로 그룹화한 것과 등석을 활용한 교차표를 그린다. (pd.crosstab([data.Sex, data.Survived], data.Pclass))
총합(margins)을 표시해라. (margins = True)
교차표의 테마는 'summer_r'로지정 (.style.background_gradient(cmap = 'summer_r'))
3등석 남자 승객은 높은 사망률을 보였고,
1, 2등석 여성은 굉장히 낮은 사망률을 보였다.
남자 승객은 1등석에 속해야 생존률이 그나마 높았다.
위 그래프는 factor plot이라고 하는데 통계학에서 특별히 활용한 적 없는 그래프라 이름은 처음 들었다.
그래프를 보니 Pclass별 생존률을 보여주었다.
sns.factorplot('Pclass', 'Survived', hue = 'Sex', data = data)
plt.show()
sns.factorplot('Pclass', 'Survived', hue = 'Sex', data = data)
-> seaborn패키지로 factorplot을 그릴것이다. (sns.factorplot())
x축과 y축은 'Pclass'와 'Survived'로 나눈다. (sns.factorplot('Pclass', 'Survived'))
범주는 성별로 나눈다. (hue = 'Sex')
데이터는 data (data = data)
plt.show()
-> 그래프를 그려라.
1등석을 이용한 여성 승객의 생존률은 95-96%에 육박한 반면,
3등석을 이용한 남성 승객의 생존률은 20%도 되지 않는 생존률을 보였다.
고로 Pclass는 중요한 feature이다.
- 3) 나이 특성: 연속형 변수
data['Age'].describe()
나이 특성에서 최소값은 0.42, 최대값은 80세였고 평균은 29.7세였다.
위 그래프는 바이올린 플롯이다.
대략적인 분포의 모양을 볼 수 있다.
f, ax = plt.subplots(1, 2, figsize = (18, 8))
sns.violinplot('Pclass', 'Age', hue = 'Survived', data = data, split = True, ax = ax[0])
ax[0].set_title('Pclass and Age vs Survived')
ax[0].set_yticks(range(0, 110, 10))
sns.violinplot('Sex', 'Age', hue = 'Survived', data = data, split = True, ax = ax[1])
ax[1].set_title('Sex and Age vs Survived')
ax[1].set_yticks(range(0, 110, 10))
plt. show()
f, ax = plt.subplots(1, 2, figsize = (18, 8))
-> 두 개의 그래프를 그릴 평면을 18*8 사이즈로 구성
sns.violinplot('Pclass', 'Age', hue = 'Survived', data = data, split = True, ax = ax[0])
-> 바이올린 플롯을 그릴 것이다. (sns.violinplot())
x축은 Pclass, y축은 Age로 바이올린 플롯을 그려라. (sns.violinplot('Pclass', 'Age'))
생존여부(Survived)로 그룹화하라. (hue = 'Survived')
데이터는 data (data = data)
split해라. (split = True)
평면 중 첫번째에 그려라. (ax = ax[0])
여기서 만약 split옵션의 디폴트값인 split = False로 설정하면 아래와 같은 그래프를 그린다.
ax[0].set_title('Pclass and Age vs Survived')
-> 첫번째 그래프의 타이틀을 'Pclass and Age vs Survived'로 지정
ax[0].set_yticks(range(0, 110, 10))
-> y축을 0부터 110까지 10의 간격으로 그리라는 뜻이다.
yticks를 지정해주지 않으면 y축을 0부터 80까지 20 간격으로 그린다.
수치를 시각적으로 편하게 확인하기 위해 set_yticks옵션을 활용해보자.
sns.violinplot('Sex', 'Age', hue = 'Survived', data = data, split = True, ax = ax[1])
-> x축을 Sex, y축을 Age, Survived로 그룹화한 바이올린 플롯을 그린다.
ax[1].set_title('Sex and Age vs Survived')
-> 두번째 그래프의 타이틀을 'Sex and Age vs Survived'로 지정
ax[1].set_yticks(range(0, 110, 10))
-> 두번째 그래프의 y축을 0부터 110까지 10의 간격으로 설정
plt.show()
-> 그래프를 보여라
바이올린 플롯 확인 결과
1) 10세 이하의 어린이는 등석에 관계없이 생존률이 높았다.
2) 20-50세 승객 중 1등석 이용객은 생존률이 매우 높았다.
3) 남성의 경우, 나이가 많을수록 생존률이 급감했다.
앞서 결측치를 확인했을 때, Age 특성에 177개의 결측치가 있었다.
177개의 결측을 모두 삭제한다면 정보 손실이 매우 크므로 결측치를 특정 값으로 대체하는 것이 좋아보인다.
일반적으로는 평균치를 대입하는 것이 맞지만, 타이타닉 데이터의 경우, 나이대 범주가 어린아이부터 노인까지 분포되어 있는 자료인데 평균 나이인 29세를 대입하는 것이 옳은 선택일까?
해당 캐글러는 그렇지 않다고 보고 데이터의 어떤 Feature를 이용해서 합리적으로 나이를 부여하고자 했다.
그 변수는 바로 'Name' 특성이었다!
Name 특성으로 나이대를 추측한다는 발상을 하다니, Name 특성을 그저 버릴 생각이었던 나는 충격을 받았다.
포스팅이 너무 길어져서 Age 특성에서 잠시 줄이고 Name 특성을 활용한 Age 결측치 대체는 다음 포스팅에서 다루어보겠다.
'연습장' 카테고리의 다른 글
[Kaggle] 캐글 상위권 코드 보고 공부하는 타이타닉 예제 심화 Feature Engineering (나이대, 요금대, 가족으로 변수 묶기/문자형 자료 변환/칼럼 삭제) (0) | 2020.11.11 |
---|---|
[Kaggle] 캐글 상위권 코드 보고 공부하는 타이타닉 예제 심화 EDA 2 (이름 특성에서 인사이트 얻기, 승선장, 가족구성원 수, 요금 특성 분석) (0) | 2020.11.11 |
[Kaggle] 타이타닉 예제 전처리 (0) | 2020.11.09 |
[Kaggle] 타이타닉 예제에서 막대그래프로 범주 살펴보기 (0) | 2020.11.07 |
[Kaggle] 파이썬에서 함수 정의해서 파이차트 만들기 (Titanic 예제 활용) (0) | 2020.11.07 |