이번 시간에는 그동안 배운
데이터 전처리, 교차검증, 학습 등의 방법을
모두 사용하여 캐글의 아주 대표적인 문제인
'타이타닉 생존자 예측'을 해보도록 하겠습니다.
자세한 이론적인 설명은 앞에서 다뤘으니
코드들 위주로 그동안 배운 이론들이 어떻게 적용되는지
간단간단하게 보고 넘어가도록 하겠습니다.
이는 '파이썬 머신러닝 완벽가이드'를 정리한 내용입니다.
먼저, 타이타닉 탑승자 데이터가 어떻게 생겼는지 살펴보도록 하겠습니다.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
titanic_df = pd.read_csv('./titanic_train.csv')
titanic_df.head(3)
print(titanic_df.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 891 non-null int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null object
4 Sex 891 non-null object
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null object
9 Fare 891 non-null float64
10 Cabin 204 non-null object
11 Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
None
위의 결과를 보면 null값이 포함된 피처들이 있습니다. Age, Cabin, Embarked Null값을 처리해보도록 하겠습니다.
#NULL 값 처리
titanic_df['Age'].fillna(titanic_df['Age'].mean(), inplace=True)
titanic_df["Cabin"].fillna('N', inplace=True)
titanic_df["Embarked"].fillna('N', inplace=True)
print('데이터 세트 Null 값 갯수 ',titanic_df.isnull().sum())
데이터 세트 Null 값 갯수 PassengerId 0
Survived 0
Pclass 0
Name 0
Sex 0
Age 0
SibSp 0
Parch 0
Ticket 0
Fare 0
Cabin 0
Embarked 0
dtype: int64
다음과 같이 Null 값을 처리 완료하였습니다. 다음으로 Age, Cabin, Embarked 피처들의 값 분류를 살펴 보겠습니다.
print(' Sex 값 분포 :\n',titanic_df['Sex'].value_counts())
print('\n Cabin 값 분포 :\n',titanic_df['Cabin'].value_counts())
print('\n Embarked 값 분포 :\n',titanic_df['Embarked'].value_counts())
Sex 값 분포 :
male 577
female 314
Name: Sex, dtype: int64
Cabin 값 분포 :
N 687
B96 B98 4
G6 4
C23 C25 C27 4
F2 3
...
E38 1
B19 1
B69 1
C49 1
B39 1
Name: Cabin, Length: 148, dtype: int64
Embarked 값 분포 :
S 644
C 168
Q 77
N 2
Name: Embarked, dtype: int64
여기서 Cabin의 값 분류에 주목해보면 속성값이 제대로 정리되지 않은 것을 볼 수 있습니다. 따라서 선실의 등급을 나타내는 첫번째 알파벳만 가져와 정리해보도록 하겠습니다.
titanic_df['Cabin']=titanic_df['Cabin'].str[:1]
print(titanic_df['Cabin'].head(3))
0 N
1 C
2 N
Name: Cabin, dtype: object
머신러닝을 통해 예측을 진행하기 이전에 먼저 어떤 유형의 승객의 생존 확률이 높았는지 그래프와 함께 살펴보도록 하겠습니다. 첫번째로 성별입니다.
titanic_df.groupby(['Sex','Survived'])['Survived'].count()
Sex Survived
female 0 81
1 233
male 0 468
1 109
Name: Survived, dtype: int64
sns.barplot(x='Sex', y = 'Survived', data=titanic_df)
위의 결과를 보면 알 수 있듯이 여성이 남성보다 생존 확률이 높았다는 사실을 알 수 있습니다.
두번째로 부입니다. 부를 측정할 수 있는 수단으로는 객실 등급을 사용하도록 하겠습니다. 성별이 생존확률에 크게 영향을 끼친 만큼 성별도 같이 고려하여 부에 따른 생존확률을 살펴보도록 하겠습니다.
sns.barplot(x='Pclass', y='Survived', hue='Sex', data=titanic_df)
앞서 살표보았듯이 여성의 생존 확률은 모든 계층에서 높고 일등급 객실 남성의 생존확률이 다른 등급에 비해 높음을 알 수 있습니다.
마지막으로 연령대별 생존확률에 대하여 살펴보겠습니다.
# 입력 age에 따라 구분값을 반환하는 함수 설정. DataFrame의 apply lambda식에 사용.
def get_category(age):
cat = ''
if age <= -1: cat = 'Unknown'
elif age <= 5: cat = 'Baby'
elif age <= 12: cat = 'Child'
elif age <= 18: cat = 'Teenager'
elif age <= 25: cat = 'Student'
elif age <= 35: cat = 'Young Adult'
elif age <= 60: cat = 'Adult'
else : cat = 'Elderly'
return cat
# 막대그래프의 크기 figure를 더 크게 설정
plt.figure(figsize=(10,6))
#X축의 값을 순차적으로 표시하기 위한 설정
group_names = ['Unknown', 'Baby', 'Child', 'Teenager', 'Student', 'Young Adult', 'Adult', 'Elderly']
# lambda 식에 위에서 생성한 get_category( ) 함수를 반환값으로 지정.
# get_category(X)는 입력값으로 'Age' 컬럼값을 받아서 해당하는 cat 반환
titanic_df['Age_cat'] = titanic_df['Age'].apply(lambda x : get_category(x))
sns.barplot(x='Age_cat', y = 'Survived', hue='Sex', data=titanic_df, order=group_names)
titanic_df.drop('Age_cat', axis=1, inplace=True)
역시나 Baby와 Elderly의 생존확률이 높았음을 알 수 있습니다. 이렇게 Sex, Age, Pclass가 생존을 좌우하는 중요한 피처임을 알 수 있었습니다.
이제 해당 피처들의 값을 LableEncoder를 사용하여 인코딩하도록 하겠습니다.
from sklearn import preprocessing
def encode_features(dataDF):
features = ['Cabin', 'Sex', 'Embarked']
for feature in features:
le = preprocessing.LabelEncoder()
le = le.fit(dataDF[feature])
dataDF[feature]=le.transform(dataDF[feature])
return dataDF
titanic_df=encode_features(titanic_df)
titanic_df.head()
Sex, Age, Pclass 피처의 값이 인코딩 되었음을 확인할 수 있습니다.
앞에서 실시한 데이터 전처리 함수들의 재사용성을 위해 transform_features() 로 통합하도록 하겠습니다.
from sklearn.preprocessing import LabelEncoder
# Null 처리 함수
def fillna(df):
df['Age'].fillna(df['Age'].mean(),inplace=True)
df['Cabin'].fillna('N',inplace=True)
df['Embarked'].fillna('N',inplace=True)
df['Fare'].fillna(0,inplace=True)
return df
# 머신러닝 알고리즘에 불필요한 속성 제거
def drop_features(df):
df.drop(['PassengerId','Name','Ticket'],axis=1,inplace=True)
return df
# 레이블 인코딩 수행.
def format_features(df):
df['Cabin'] = df['Cabin'].str[:1]
features = ['Cabin','Sex','Embarked']
for feature in features:
le = LabelEncoder()
le = le.fit(df[feature])
df[feature] = le.transform(df[feature])
return df
# 앞에서 설정한 Data Preprocessing 함수 호출
def transform_features(df):
df = fillna(df)
df = drop_features(df)
df = format_features(df)
return df
# 원본 데이터를 재로딩 하고, feature데이터 셋과 Label 데이터 셋 추출.
titanic_df = pd.read_csv('./titanic_train.csv')
y_titanic_df = titanic_df['Survived']
X_titanic_df= titanic_df.drop('Survived',axis=1)
X_titanic_df = transform_features(X_titanic_df)
이제 본격적으로 학습을 진행해보도록 하겠습니다. 학습은 의사결정 트리, 랜덤포레스트, 로지스틱 회귀를 이용하도록 하겠습니다. 이에 대한 자세한 내용은 뒤에서 다루도록 하겠습니다.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test=train_test_split(X_titanic_df, y_titanic_df, \
test_size=0.2, random_state=11)
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# 결정트리, Random Forest, 로지스틱 회귀를 위한 사이킷런 Classifier 클래스 생성
dt_clf = DecisionTreeClassifier(random_state=11)
rf_clf = RandomForestClassifier(random_state=11)
lr_clf = LogisticRegression()
# DecisionTreeClassifier 학습/예측/평가
dt_clf.fit(X_train , y_train)
dt_pred = dt_clf.predict(X_test)
print('DecisionTreeClassifier 정확도: {0:.4f}'.format(accuracy_score(y_test, dt_pred)))
# RandomForestClassifier 학습/예측/평가
rf_clf.fit(X_train , y_train)
rf_pred = rf_clf.predict(X_test)
print('RandomForestClassifier 정확도:{0:.4f}'.format(accuracy_score(y_test, rf_pred)))
# LogisticRegression 학습/예측/평가
lr_clf.fit(X_train , y_train)
lr_pred = lr_clf.predict(X_test)
print('LogisticRegression 정확도: {0:.4f}'.format(accuracy_score(y_test, lr_pred)))
DecisionTreeClassifier 정확도: 0.7877
RandomForestClassifier 정확도:0.8547
LogisticRegression 정확도: 0.8492
다음으로는 앞에서 배운 교차검증을 통해 조금 더 모델을 평가해보도록 하겠습니다. 앞서 배운 KFold, cross_val_score(), GridSearchCV()를 모두 사용해보겠습니다.
KFold
from sklearn.model_selection import KFold
# KFold 사용
def exec_kfold(clf, folds=5):
kfold=KFold(n_splits=folds)
scores=[]
for iter_count, (train_index, test_index) in enumerate(kfold.split(X_titanic_df)):
X_train, X_test = X_titanic_df.values[train_index], X_titanic_df.values[test_index]
y_train, y_test = y_titanic_df.values[train_index], y_titanic_df.values[test_index]
# Classifier 학습, 예측, 정확도 계산
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
accuracy = accuracy_score(y_test, predictions)
scores.append(accuracy)
print("교차 검증 {0} 정확도: {1:.4f}".format(iter_count, accuracy))
# 5개 fold에서의 평균 정확도 계산.
mean_score = np.mean(scores)
print("평균 정확도: {0:.4f}".format(mean_score))
# exec_kfold 호출
exec_kfold(dt_clf , folds=5)
from sklearn.model_selection import KFold
# exec_kfold 호출
exec_kfold(dt_clf , folds=5)
교차 검증 0 정확도: 0.7542
교차 검증 1 정확도: 0.7809
교차 검증 2 정확도: 0.7865
교차 검증 3 정확도: 0.7697
교차 검증 4 정확도: 0.8202
평균 정확도: 0.7823
cross_val_score()
# cross_val_score 사용
from sklearn.model_selection import cross_val_score
scores = cross_val_score(dt_clf, X_titanic_df , y_titanic_df , cv=5)
for iter_count,accuracy in enumerate(scores):
print("교차 검증 {0} 정확도: {1:.4f}".format(iter_count, accuracy))
print("평균 정확도: {0:.4f}".format(np.mean(scores)))
교차 검증 0 정확도: 0.7430
교차 검증 1 정확도: 0.7753
교차 검증 2 정확도: 0.7921
교차 검증 3 정확도: 0.7865
교차 검증 4 정확도: 0.8427
평균 정확도: 0.7879
GridSearchCV
# GridSearchCV 사용
from sklearn.model_selection import GridSearchCV
parameters = {'max_depth':[2,3,5,10],
'min_samples_split':[2,3,5], 'min_samples_leaf':[1,5,8]}
grid_dclf = GridSearchCV(dt_clf , param_grid=parameters , scoring='accuracy' , cv=5)
grid_dclf.fit(X_train , y_train)
print('GridSearchCV 최적 하이퍼 파라미터 :',grid_dclf.best_params_)
print('GridSearchCV 최고 정확도: {0:.4f}'.format(grid_dclf.best_score_))
best_dclf = grid_dclf.best_estimator_
# GridSearchCV의 최적 하이퍼 파라미터로 학습된 Estimator로 예측 및 평가 수행.
dpredictions = best_dclf.predict(X_test)
accuracy = accuracy_score(y_test , dpredictions)
print('테스트 세트에서의 DecisionTreeClassifier 정확도 : {0:.4f}'.format(accuracy))
GridSearchCV 최적 하이퍼 파라미터 : {'max_depth': 3, 'min_samples_leaf': 5, 'min_samples_split': 2}
GridSearchCV 최고 정확도: 0.7992
테스트 세트에서의 DecisionTreeClassifier 정확도 : 0.8715
이렇게 그동안 우리가 배운 방법들을
실제 데이터에 적용해봤습니다. 이렇게 데이터에 적용하니
조금이나마 제가 배운 내용이 어떻게 활용되고 왜 배운건지
더욱 확 와닿게 되는 것 같습니다.
다음 시간부터는 이제 평가 기법에 대하여
본격적으로 다뤄보도록 하겠습니다.
'파이썬 머신러닝 완벽가이드' 카테고리의 다른 글
3.2 평가(F1 스코어, ROC와 AUC) (0) | 2021.11.21 |
---|---|
3.1 평가(정밀도/재현율) (0) | 2021.11.21 |
2.3 데이터 전처리 (0) | 2021.11.14 |
2.2 교차검증 (0) | 2021.11.14 |
2.1 첫 번째 머신러닝 만들어 보기 - 붓꽃 품종 예측하기 (0) | 2021.11.13 |