* 이번 타이타닉 데이터 분석은 오직 train/test data로만 나눴고, test 결과는 다소 test set에 과적합 되었습니다.
또한 평가지표는 정확도(Accuracy)만 측정되어 정확한 평가가 이루어지지 않았음을 미리 알려드립니다.
1. 분석 배경
1) 데이터 살피기
df = pd.read_csv('train (1).csv')
df.head(3)
- PassengerId : 탑승자 데이터 일련번호
- Survived : 생존여부 (0=사망 1=생존)
- Pclass : 티켓의 선실 등급 (1=일등석 2=이등석 3=삼등석)
- Name : 탑승자 이름
- Sex : 탑승자 성별
- Age : 탑승자 나이
- SibSp : 같이 탑승한 형제자매 또는 배우자 인원수
- Parch : 같이 탑승한 부모님 또는 어린이 인원수
- Ticket : 티켓 번호
- Fare : 요금
- Cabin : 선실번호
- Embarked : 중간 정착 항구(C=Cherbourg Q=Queenstown S=Southampton)
▶결과
( Target : Survived ) | 숫자형 | 카테고리형 |
필요한 feature | Pclass, Age, SibSp, Parch, Fare | Sex, Cabin, Embarked |
필요없는 feature | PassengerId | Name , Ticket |
# 필요없는 feature 제거
df.drop(['PassengerId','Name','Ticket'],axis=1,inplace=True)
df
2) 데이터 결측치와 타입 확인 후 처리
df.info()
▶결과
* 결측치 있는 Feature : Age , Cabin, Embarked |
# 결측값 정리
df['Age'].fillna(df['Age'].mean(),inplace=True)
df['Cabin'].fillna('N', inplace=True)
df['Embarked'].fillna('N', inplace=True)
print('총 결측치 수:',df.isnull().sum().sum())
# 문자열 피처
print('Sex 값 분포 :\n',df['Sex'].value_counts())
print('\nCabin 값 분포 :\n', df['Cabin'].value_counts())
print('\nEmbarked 값 분포 :\n', df['Embarked'].value_counts())
# Cabin 앞글자는 선실 등급으로 보임
df['Cabin'] = df['Cabin'].str[:1]
df['Cabin'].head()
2. 분석 목표
필요한 feature들로 생존율 예측하기
3. 데이터 시각화/ 모델링(스토리텔링)
1) 관련있는 feautres 확인
- 여성과 아이들, 노약자가 제일 먼저 구조 대상일 것이다.
- 그리고 아마 그 다음이 부자와 유명인 이었을 것이다.
- 삼등실에 탄 많은 가난한 사람들의 사망률이 높을 것이다.
성별과 나이, 객실등급이 생존 확률에 어떤 영향을 미쳤는지 비교해 보겠습니다.
df.groupby(['Sex','Survived'])['Survived'].count()
# 성별에 따른 생존율
sns.barplot(x='Sex',y='Survived',data=df)
▶결과
전체적으로 남성의 수(577명)가 여성의 수(314명)보다 많지만, 생존률은 남성(약 19%)보다 여성(약 75%)이 훨씬 크다. 결론 : 성별은 생존율에 영향을 끼친다. |
# 객실 등급과 성별에 따른 생존율
sns.barplot(x='Pclass', y='Survived', hue='Sex',data=df)
▶결과
여성의 경우 1,2 등실에 따른 생존율 차이가 많이 없으나, 3등실의 경우 생존율이 상대적으로 많이 떨어진다. 남성의 경우 일등실의 생존 확률이 2,3 등실보다 2배 이상 높습니다. 결론 : 객실 등급은 생존율에 영향을 끼친다. |
# 나이에 따른 생존확률
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
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 반환
df['Age_cat'] = df['Age'].apply(lambda x: get_category(x))
sns.barplot(x='Age_cat',y='Survived',hue='Sex',data=df, order=group_names)
df.drop('Age_cat', axis=1, inplace=True)
* seaborn은 barplot() 함수를 사용할 때 각 막대에 기본적으로 오차막대(error bar)가 함께 나타나도록 되어 있다.
그리고 이 오차막대를 그리는 범위는 기본적으로 ‘부트 스트랩 신뢰구간(Bootstrap confidence interval)’이라는 것을 사용한다. “이 데이터를 기반으로 유사한 상황의 95 %가 이 범위 내에서 결과를 얻을 것”을 의미한다.
▶결과
여성의 경우 Elderly의 생존율은 거의 98~9%로 매우 높다. 여자 Baby는 생존율이 높지만 여자 Child는 생존율이 낮다. 남성의 경우 baby, Child 순으로 생존율이 높으며, Teenager가 생존율이 가장 낮다. 결론 : 이때까지 분석한 결과 Sex, Age, PClass 등이 중요하게 생존과 관련있는 feature임을 알 수 있다. |
2) 문자열 카테고리 Label encoding
문자열 카테고리 숫자형으로 바꾸기
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
df = encode_features(df)
df.head()
3) 머신러닝 알고리즘을 이용해 생존자 예측하기
1. Decision Tree/Random Forest/Logistic Regression 최적화X
2. Decision Tree/Random Forest/Logistic Regression & KFoldCV
3. Decision Tree/Random Forest/Logistic Regression & cross_val_score()
4. Decision Tree/Random Forest/Logistic Regression & GridSearchCV
1. 최적화 X (before)
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# 사이킷런 Classifir 클래스 생성
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('DecisionTree 정확도 : {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('RandomForest 정확도 : {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('Logistic Regression 정확도 : {0:.4f}'.format(accuracy_score(y_test, lr_pred)))
2. DecisionTree / RandomForest / Logistic Regression & KFold CV
# DecisionTree & KFold
from sklearn.model_selection import KFold
def exec_kfold(clf, folds=5):
# 폴드 세트를 5개인 KFold객체를 생성, 폴드 수만큼 예측결과 저장을 위한 리스트 객체 생성.
kfold = KFold(n_splits=folds)
scores = []
# KFold 교차 검증 수행.
for iter_count, (train_index, test_index) in enumerate(kfold.split(feature)):
# X_titanic_df 데이터에서 교차 검증별로 학습과 검증 데이터를 가리키는 index 생성
X_train, X_test = feature.values[train_index], feature.values[test_index]
y_train, y_test = target.values[train_index], target.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)
# RandomForest & KFold
# exec_kfold 호출
exec_kfold(rf_clf, folds=5)
# Logistic Regression & KFold
# exec_kfold 호출
exec_kfold(lr_clf, folds=5)
DecisionTree / RandomForest / Logistic Regression & cross_val_score()
# Decision Tree & cross_val_score()
from sklearn.model_selection import cross_val_score
scores = cross_val_score(dt_clf, feature, target, cv=5)
for iter_count, accuracy in enumerate(scores):
print("교차검증 {0} 정확도 : {1:.4f}".format(iter_count, accuracy))
print("평균 정확도: {0:.4f}".format(np.mean(scores)))
# RandomForest Tree & cross_val_score()
from sklearn.model_selection import cross_val_score
scores = cross_val_score(rf_clf, feature, target, cv=5)
for iter_count, accuracy in enumerate(scores):
print("교차검증 {0} 정확도 : {1:.4f}".format(iter_count, accuracy))
print("평균 정확도: {0:.4f}".format(np.mean(scores)))
# Logistic Regression & cross_val_score()
from sklearn.model_selection import cross_val_score
scores = cross_val_score(lr_clf, feature, target, cv=5)
for iter_count, accuracy in enumerate(scores):
print("교차검증 {0} 정확도 : {1:.4f}".format(iter_count, accuracy))
print("평균 정확도: {0:.4f}".format(np.mean(scores)))
DecisionTree & GridSearchCV
# DecisionTree & 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('test set 정확도 :{0:.4f}'.format(accuracy))
RandomForest & GridSearchCV
# RandomForest & 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_rclf = GridSearchCV(rf_clf, n_jobs=-1, param_grid=parameters, scoring='accuracy', cv=5)
grid_rclf.fit(X_train, y_train)
print('GridSearchCV 최적 하이퍼 파라미터:', grid_rclf.best_params_)
print('GridSearchCV 최고 정확도:{0:.4f}'.format(grid_rclf.best_score_))
best_rclf = grid_rclf.best_estimator_
#GridSearchCV의 최적 하이퍼 파라미터로 학습된 Estimator로 예측 및 평가 수행.
rpredictions = best_rclf.predict(X_test)
accuracy = accuracy_score(y_test, rpredictions)
print('test set 정확도 :{0:.4f}'.format(accuracy))
▶결과
분류모델 | 최적화 X | KFold CV (k=5) | cross_val_score(cv=5) | GridSearch CV (cv=5) |
DecisionTree Accuracy | 78.77 % | 78.23 % | 78.79 % | 82.12 % |
RandomForest Accuracy | 83.24 % | 81.48 % | 81.37 % | 84.92 % |
Logistic Regression Accuracy | 82.68 % | 78.34 % | 78.45% | x |
4. 결과요약 및 제안(의사결정)
RandomForest 모델로 GridSearch CV (최적화) 했을 때 84.92%의 최고 성능을 보입니다.
그래프를 보면 전체적으로 RandomForest 모델을 사용했을 때, GridSearchCV로 최적화 했을 때 좋은 성능을 냅니다.
(물론 타이타닉의 test 데이터 수가 작기도 하고, 반복적인 test set를 이용해 예측한 과적합된 결과라 확실한 성능 결과라고는 할 수 없습니다.)
※ 예측 모델을 만든 Features 로는 객실등급, 탑승객 성별, 나이, 형제자매 배우자 수, 부모자식 수, 탑승요금, 객실번호, 중간 정착 항구 가 있습니다. (Pclass, Sex, Age, SibSp, Parch, Fare, Cabin, Embarked)