데이터셋 확인
탐색적 데이터 분석(exploratory data analysis)
feature engineering
model 만들기
모델 학습 및 예측
모델 평가
# 결측치 시각화 패키지
# pip install missingno
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('seaborn') # matplotlib 의 기본 scheme 말고 seaborn scheme 을 세팅, 또는 ggplot style 사용
import missingno as msno
sns.set(font_scale=2.5) # 개별적인 font size 를 지정할 필요없이 seaborn 의 font_scale 을 사용하면 편리
import warnings #ignore warnings
warnings.filterwarnings('ignore')
%matplotlib inline
train = pd.read_csv('titanic/train.csv')
test = pd.read_csv('titanic/test.csv')
# train data set 확인
train.head()
# test data set 확인
test.head()
# test data set에는 Survived 열이 없음 (예측하려는 target label 이므로)
# train data set의 형상정보 확인 (데이터의 행,열 크기)
train.shape
# (행, 열)
test.shape
# train data set의 DataFrame 정보 확인
train.info()
# isnull : 결측값 여부
train.isnull().sum()
# 177개의 나이, 687개의 Cabin, 2개의 Embarked에 대한 데이터가 존재하지 않음
test.isnull().sum()
# NaN 비율 구하는 함수 생성
def nan_prop(data):
for col in data.columns:
is_null_sum = data[col].isnull().sum()
col_total_row = data[col].shape[0]
is_null_prop = 100 * ( is_null_sum / col_total_row)
msg = 'column: {:>10}\t Percent of NaN value: {:.2f}%'.format(col, is_null_prop)
print(msg)
# train data set의 NaN 비율
nan_prop(train)
# tset data set의 NaN 비율
nan_prop(test)
# msno.matrix : 매트릭스 형태로 결측치 시각화
# train data set 결측치 시각화
msno.matrix(df=train.iloc[:, :], figsize=(8, 8), color=(0.5, 0.5, 0.5))
# 그래프의 마지막 열은 각 데이터마다 활용할 수 있는 변수의 갯수를 시각화한 것
# 현재 두 개의 변수에서 데이터 결측치가 있으므로 최소 활용 변수는 10개, 최대 활용 변수는 12개
# test data set 결측치 시각화
msno.matrix(df=test.iloc[:, :], figsize=(8, 8), color=(0.5, 0.5, 0.5))
# train data set 결측치 확인
# msno.bar : bar 형태로 결측치 시각화
msno.bar(df=train.iloc[:, :], figsize=(8, 8), color=(0.8, 0.5, 0.2))
# test data set 결측치 확인
msno.bar(df=test.iloc[:, :], figsize=(8, 8), color=(0.8, 0.5, 0.2))
f, ax = plt.subplots(1, 2, figsize=(18,8)) # f:field 하나에 2개의 ax를 그릴 것이다
train['Survived'].value_counts().plot.pie(explode=[0, 0.1], autopct='%1.1f%%', ax=ax[0], shadow=True)
ax[0].set_title('Pie plot - Survived')
ax[0].set_ylabel('')
sns.countplot('Survived', data=train, ax=ax[1])
ax[1].set_title('Count plot - Survived')
plt.show()
# 생사여부 두 개의 막대차트로 표시하는 함수 생성
def bar_chart(feature):
survived = train[train['Survived']==1][feature].value_counts()
dead = train[train['Survived']==0][feature].value_counts()
df = pd.DataFrame([survived, dead])
df.index = ['Survived', 'Dead']
df.plot(kind='bar', stacked=True, figsize=(10,5))
bar_chart('Sex')
# 여성이 남성보다 생존할 가능성이 더 높음
bar_chart('Pclass')
# first class가 다른 등급보다 생존할 가능성이 더 높음
bar_chart('SibSp')
# 형제나 배우자가 있는 탑승객이 생존할 가능성이 더 높음
bar_chart('Parch')
# 혼자인 사람보다 부모나 자식이 있는 사람들이 생존할 가능성이 더 높음
bar_chart('Embarked')
# S 선착장 탑승자의 경우 생존확률이 더 높음
# Both Sex and Pclass - seaborn factorplot
# hue : 카테고리형 데이터가 섞여있는 경우, hue 인수에 카테고리 변수 이름을 지정하여 카테고리 값에 따라 색상을 다르게 할 수 있음
sns.factorplot('Pclass', 'Survived', hue='Sex', data=train, sixe=6, aspect=1.5)
# 모든 클래스에서 여성의 생존 확률이 남성보다 높음
# 성별 상관 없이 클래스가 높을수록 생존 확률 높음
# hue 대신 column 그래프
# column별로 그래프 시각화
sns.factorplot(x='Sex', y='Survived', col='Pclass', data=train, satureation=.5, size=9, aspect=1)
# Pclass, Sex, Age 3개 변수 그래프 seaborn 의 violinplot
f, ax=plt.subplots(1, 2, figsize=(18,8)) # f:field 하나에 2개의 ax를 그릴 것이다
sns.violinplot("Pclass","Age", hue="Survived",
data=train, scale='count', 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=train, scale='count', split=True,ax=ax[1])
ax[1].set_title('Sex and Age vs Survived')
ax[1].set_yticks(range(0,110,10))
plt.show()
train.head(10)
# 훈련 및 테스트 데이터 세트 결합
train_test_data = [train, test]
# Name값에서 성별 정보 추출
# 정규표현식으로 [문자]. 으로 끝나는 문자열 추출
for dataset in train_test_data:
dataset['Title'] = dataset['Name'].str.extract('([A-za-z]+)\.', expand=False)
# Name값에서 추출한 성별정보의 갯수 확인
# train data set
train['Title'].value_counts()
# test data set
test['Title'].value_counts()
# Title mapping
title_mapping = {"Mr":0, "Miss":1, "Mrs":2,
"Master":3, "Dr":3, "Rev":3, "Col": 3, 'Ms': 3, 'Mlle': 3, "Major": 3, 'Lady': 3, 'Capt': 3,
'Sir': 3, 'Don': 3, 'Mme':3, 'Jonkheer': 3, 'Countess': 3 }
# 반복문으로 데이터에 Title mapping 적용
for dataset in train_test_data:
dataset['Title'] = dataset['Title'].map(title_mapping)
# train data set 확인
train.head()
# 성별호칭에 따른 생존여부 그래프로 확인
def bar_chart(feature):
survived = train[train['Survived'] == 1][feature].value_counts()
dead = train[train['Survived'] == 0][feature].value_counts()
df = pd.DataFrame([survived, dead])
df.index = ['Survived','Dead']
df.plot(kind='bar',stacked=True, figsize=(10,5))
bar_chart('Title')
# Title 값이 생존여부에 영향을 끼치지 않는 것을 확인
# 데이터 셋에서 불필요한 feature 삭제
train.drop('Name', axis=1, inplace=True)
test.drop('Name', axis=1, inplace=True)
train.head()
# 성별에 숫자 매핑
sex_mapping = {'male': 0, 'female':1}
# 반복문으로 매핑결과 데이터에 적용
for dataset in train_test_data:
dataset['Sex'] = dataset['Sex'].map(sex_mapping)
# 그래프로 확인
bar_chart('Sex')
# 여성의 생존율이 높음
# Missing Age를 각 Title에 대한 연령의 중간값으로 대체(Mr, Mrs, Miss, Others)
# 그룹단위 통계량 추가 transform() - https://rfriend.tistory.com/403
# train data set
train['Age'].fillna(train.groupby('Title')['Age'].transform('median'), inplace=True)
# test data set
test['Age'].fillna(test.groupby('Title')['Age'].transform('median'), inplace=True)
# 생존여부 시각화
facet = sns.FacetGrid(train, hue='Survived', aspect=4)
facet.map(sns.kdeplot, 'Age', shade=True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
sns.axes_style("darkgrid")
plt.show()
# 나이대별로 구분하여 그래프 확대 출력 (0~20세)
facet = sns.FacetGrid(train, hue='Survived', aspect=4)
facet.map(sns.kdeplot, 'Age', shade=True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
plt.xlim(0,20)
plt.style.use('ggplot')
# 나이대별로 구분하여 그래프 확대 출력 (20~30세)
facet = sns.FacetGrid(train, hue='Survived', aspect=4)
facet.map(sns.kdeplot, 'Age', shade=True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
plt.xlim(20,30)
# 나이대별로 구분하여 그래프 확대 출력 (30~40세)
facet = sns.FacetGrid(train, hue='Survived', aspect=4)
facet.map(sns.kdeplot, 'Age', shade=True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
plt.xlim(30,40)
# 나이대별로 구분하여 그래프 확대 출력 (40~60세)
facet = sns.FacetGrid(train, hue='Survived', aspect=4)
facet.map(sns.kdeplot, 'Age', shade=True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
plt.xlim(40,60)
# 나이대별로 구분하여 그래프 확대 출력 (60세 이상)
facet = sns.FacetGrid(train, hue="Survived", aspect=4)
facet.map(sns.kdeplot, 'Age', shade=True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
plt.xlim(60)
# 나이대별 카테고라이징
for dataset in train_test_data:
dataset.loc[ dataset['Age'] <=16, 'Age']=0,
dataset.loc[(dataset['Age'] > 16) & (dataset['Age'] <=26), 'Age'] = 1,
dataset.loc[(dataset['Age'] > 26) & (dataset['Age'] <=36), 'Age'] = 2,
dataset.loc[(dataset['Age'] > 36) & (dataset['Age'] <=62), 'Age'] = 3,
dataset.loc[(dataset['Age'] > 62), 'Age'] = 4
train.head()
bar_chart('Age')
# 나이대별 생사여부 확인
survived = train[train['Survived']==1]['Age'].value_counts()
dead = train[train['Survived']==0]['Age'].value_counts()
# 나이대별 생존자
survived
# 나이대별 사망자
dead
# 좌석별 승선 항구 확인하기
Pclass1 = train[train['Pclass']==1]['Embarked'].value_counts()
Pclass2 = train[train['Pclass']==2]['Embarked'].value_counts()
Pclass3 = train[train['Pclass']==3]['Embarked'].value_counts()
Pclass1
# 클래스별 승선 항구를 확인할 수 있다
# DataFrame으로 만들어 인덱스 주기
df = pd.DataFrame([Pclass1, Pclass2, Pclass3])
df.index = ['1st class', '2nd class', '3rd class']
df
# 시각화
df.plot(kind='bar', stacked=True, figsize=(10,5))
# Embarked 정보가 없을 경우 S 항구로 대치
# 반복문으로 전체 자료에 적용
for dataset in train_test_data:
dataset['Embarked'] = dataset['Embarked'].fillna('S')
train.head()
# 머신러닝 Classifier를 위해 텍스트 숫자 변경(매핑)
embarked_mapping = {'S':0, 'C':1, 'Q':2}
# map 함수 사용해서 처리
for dataset in train_test_data:
dataset['Embarked'] = dataset['Embarked'].map(embarked_mapping)
train.head()
# train data set 중앙값 확인
train.groupby('Pclass')['Fare'].median()
# train data set 평균 확인
train.groupby('Pclass')['Fare'].mean()
# 평균과 중앙값 중 각 클래스 값을 더 대표할 수 있는 값으로 선택
# test data set 중앙값 확인
test.groupby('Pclass')['Fare'].median()
# 탑승권 가격이 결측값일 경우, 좌석 등급별 중간값으로 대치
# train data set
train["Fare"].fillna(train.groupby('Pclass')['Fare'].transform('median'), inplace=True)
# test data set
test["Fare"].fillna(test.groupby('Pclass')['Fare'].transform('median'), inplace=True)
# 시각화
# FacetGrid(data, row, col, hue) : 다중 플롯 그리드를 만들어서 여러가지 쌍 관계를 표현하기 위한 그리드 Class. 도화지에 축을 나누는것과 같음
# Seaborn에서 Multi-plot grid로 조건부 관계를 여러가지를 동시에 플롯팅 할 수 있는 클래스 중 하나
facet = sns.FacetGrid(train, hue="Survived", aspect=4) # 데이터를 survived로 나누겠다
facet.map(sns.kdeplot, 'Fare', shade=True) # FacetGrid의 객체 facet에 'map'함수를 이용해 어떤 그래프를 그릴 것인지 명시 & 변수명 명시
facet.set(xlim=(0, train['Fare'].max()))
facet.add_legend()
plt.show()
# x축 범위 설정해서 원하는 운임구간의 생존여부 확인
facet = sns.FacetGrid(train, hue="Survived", aspect=4)
facet.map(sns.kdeplot, 'Fare', shade=True)
facet.set(xlim=(0, train['Fare'].max()))
facet.add_legend()
plt.xlim(0,40)
# x축 범위 설정해서 원하는 운임구간의 생존여부 확인
facet = sns.FacetGrid(train, hue="Survived", aspect=4)
facet.map(sns.kdeplot, 'Fare', shade=True)
facet.set(xlim=(0, train['Fare'].max()))
facet.add_legend()
plt.xlim(0,100)
# 탑승권 최고 금액 확인하기(웃돈을 얹어서 탑승권을 구매한 경우)
facet = sns.FacetGrid(train, hue="Survived", aspect=4)
facet.map(sns.kdeplot, 'Fare', shade=True)
facet.set(xlim=(0, train['Fare'].max()))
facet.add_legend()
# 탑승권 최고 금액 확인하기 -> 탑승권의 갯수가 0이 되는(그 가격의 탑승권이 없다!) 탑승권의 가격
plt.xlim(0)
# binning을 사용하여 각 구간별 탑승권 가격을 카테고라이징
for dataset in train_test_data:
dataset.loc[ dataset['Fare'] <=17, 'Fare'] = 0,
dataset.loc[(dataset['Fare'] > 17) & (dataset['Fare'] <=30), 'Fare'] = 1,
dataset.loc[(dataset['Fare'] > 30) & (dataset['Fare'] <=100), 'Fare'] = 2,
dataset.loc[ dataset['Fare'] > 100, 'Fare'] = 3
train['Cabin'].head()
# 반복문을 통해 객실번호의 알파벳과 숫자 분리 후, 알파벳만 뽑아오기
for dataset in train_test_data:
dataset['Cabin'] = dataset['Cabin'].str[:1]
train['Cabin'].head()
# 클래스별로 객실 종류 count
Pclass1 = train[train['Pclass']==1]['Cabin'].value_counts()
Pclass2 = train[train['Pclass']==2]['Cabin'].value_counts()
Pclass3 = train[train['Pclass']==3]['Cabin'].value_counts()
df = pd.DataFrame([Pclass1, Pclass2, Pclass3])
df.index = ['1st class', '2nd class', '3rd class']
df.plot(kind='bar', stacked=True, figsize=(10,5))
# classifier를 위해 매핑
# feature scaling : raw data 전처리하는 과정 (feature들의 크기, 범위 정규화)/ 소수점 사용
# 숫자의 범위가 비슷하지 않으면 먼 거리에 있는 데이터를 조금 더 중요하게 생각할 수 있음 주의
cabin_mapping = {'A':0, 'B':0.4, 'C':0.8, 'D':1.2, 'E':1.6, 'F':2, 'G':2.4, 'T': 2.8}
for dataset in train_test_data:
dataset['Cabin'] = dataset['Cabin'].map(cabin_mapping)
# Cabin의 missing field는 1등급 2등급 3등급 클래스와 밀접한 관계
# 각 클래스별 cabin의 중간값을 missing value 처리
train['Cabin'].fillna(train.groupby('Pclass')['Cabin'].transform('median'), inplace=True)
test['Cabin'].fillna(test.groupby('Pclass')['Cabin'].transform('median'), inplace=True)
train.tail(10)
train.head()
# 혼자타면 SibSp, Parch 모두 0으로 표시되므로 +1 해주기
train['FamilySize'] = train['SibSp'] + train['Parch'] + 1
test['FamilySize'] = test['SibSp'] + test['Parch'] + 1
# 시각화
facet = sns.FacetGrid(train, hue="Survived", aspect=4)
facet.map(sns.kdeplot, 'FamilySize', shade=True)
facet.set(xlim=(0, train['FamilySize'].max()))
facet.add_legend()
# 0 : 사망 / 1: 생존
# 혼자 승선한 경우, 가족이 한 명 이상 함께 승선한 경우보다 생존율이 낮다
# mapping
# feature scaling
family_mapping = {1: 0, 2: 0.4, 3: 0.8, 4: 1.2, 5: 1.6, 6: 2, 7: 2.4, 8: 2.8, 9: 3.2, 10: 3.6, 11: 4}
for dataset in train_test_data:
dataset['FamilySize'] = dataset['FamilySize'].map(family_mapping)
dataset['FamilySize'].head()
train.head()
# 불필요한 데이터 삭제 : drop
# Ticket, SibSp, Parch, PassengerId 정보 제거
features_drop = ['Ticket', 'SibSp', 'Parch', 'PassengerId']
train = train.drop(features_drop, axis=1)
test = test.drop(features_drop, axis=1)
train.head()
test.head()
from sklearn.ensemble import RandomForestClassifier # randomforestclassfier
from sklearn import metrics # 모델 평가를 위해 사용
from sklearn.model_selection import train_test_split # traning set을 쉽게 나눠주는 함수
model = RandomForestClassifier()
# 정답과 공부할 문제 분리
train_data = train.drop('Survived', axis=1)
target = train['Survived']
train_data.shape, target.shape
train_data.head(10)
# train - Title의 결측값 채우기
train_data['Title'] = train['Title'].fillna(0)
# 훈련: model에 fit 시키기
model.fit(train_data, target)
test['Title'] = test['Title'].fillna(0)
test
# 예측
prediction = model.predict(test)
# 정확도 측정
accuracy = round(model.score(train_data, target) * 100, 2)
print("Accuracy : ", accuracy, "%")
test2 = pd.read_csv('titanic/test.csv')
submission = pd.DataFrame(
{
"PassengerId":test2["PassengerId"], # 앞에서 PassendgerId 삭제했으므로 다시 불러 옴
"Survived":prediction
}
)
submission.to_csv('submission_rf_20200727.csv', index=False)
submission
# 캐글에 데이터 업로드해서 등수 확인해보기