www.kaggle.com/ash316/eda-to-prediction-dietanic
(※ 오늘은 이 캐글러의 공유 코드를 활용해 공부하는 내용입니다.)
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)
이번엔 3장 Predictive Modeling과 4장 중요한 특성 추출을 동시에 진행해보려 한다.
3장. Predictive Modeling
1. Algorithms
캐글러가 사용한 알고리즘은 총 6가지이다.
1) Logistic Regression
2) Support Vector Machine
3) Random Forest
4) K-Nearest Neighbors
5) Naive Bayes
6) Decision Tree
추가적으로, Voting, Bagging, AdaBoost와 GradientBoost, 가능하다면 XGboost까지 사용해볼까 한다.
1) 머신러닝 패키지 불러오기
머신러닝 패키지는 대부분 scikit-learn에서 제공한다.
# 패키지 불러오기
from sklearn.linear_model import LogisticRegression
from sklearn import svm
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn import metrics
from sklearn.metrics import confusion_matrix
from sklearn.linear_model import LogisticRegression
-> sklearn의 linear_model 패키지에서 LogisticRegression() 함수를 불러온다.
나머지도 전부 그런식으로 특정 함수들을 이용할 수 있도록 하는 것이다.
2) train 데이터로 train, test 데이터 나누기
titanic에서 주어진 'train.csv' 데이터로 모델을 훈련시키기 위해서 train.csv 데이터를 훈련데이터와 테스트 데이터로 분류한다.
train, test = train_test_split(data, test_size = 0.3, random_state = 0, stratify = data['Survived'])
train_X = train[train.columns[1:]]
train_Y = train[train.columns[:1]]
test_X = test[test.columns[1:]]
test_Y = test[test.columns[:1]]
X = data[data.columns[1:]]
Y = data['Survived']
train, test = train_test_split(data, test_size = 0.3, random_state = 0, stratify = data['Survived'])
-> train_test_split() 함수로 훈련, 테스트 데이터를 분류한다.
훈련, 테스트 데이터로 data 데이터를 분류해서 각각 train, test 라는 이름으로 저장해라.
( train, test = train_test_split(data) )
테스트 데이터는 전체 데이터의 30%를 쓸 것 ( test_size = 0.3 )
분류할 때 사용하는 일종의 random seed는 0번으로 해라. (random_state = 0) (0 말고 다른 어떤 번호를 지정해도 상관 없다.)
Survived 칼럼을 기준으로 층화추출법으로 데이터를 추출하라. ( stratify = data['Survived'] )
train_X = train[train.columns[1:]]
-> 훈련에 사용할 feature는 train 데이터의 두번째 칼럼부터 끝까지
train_Y = train[train.columns[:1]]
-> 훈련에 사용할 target은 train 데이터의 첫번째 칼럼만
test_X = test[test.columns[1:]]
-> 테스트에 사용할 feature는 test 데이터의 두번째 칼럼부터 끝까지
test_Y = test[test.columns[:1]]
-> 테스트에 사용할 target은 test 데이터의 첫번째 칼럼만
X = data[data.columns[1:]]
-> 데이터의 두번째 칼럼부터 끝까지 칼럼들을 X라고 저장 (Feature는 X)
Y = data['Survived']
-> 데이터의 Survived 칼럼은 Y라고 저장 (target은 Y)
3) Radial SVM
#Radial SVM
model = svm.SVC(kernel = 'rbf', C = 1, gamma = 0.1)
model.fit(train_X, train_Y)
prediction1 = model.predict(test_X)
print('Accuracy for rbf SVM is', metrics.accuracy_score(prediction1, test_Y))
model = svm.SVC(kernel = 'rbf', C = 1, gamma = 0.1)
-> svm패키지의 SVC() 함수로 서포트벡터머신을 활용할 것이고 그 모델을 model이라고 저장한다. (model = svm.SVC())
SVM기법 중 Radial을 사용할 것이다. (kernel = 'rbf')
tuning parameter는 C = 1, gamma = 0.1로 설정한다. (C = 1, gamma = 0.1)
model.fit(train_X, train_Y)
-> radial-SVM 모델을 훈련데이터의 feature와 target에 적용해 모델을 훈련시킨다.
prediction1 = model.predict(test_X)
-> 훈련한 모델 model로 test데이터의 feature에 적용해서 결과를 예측해라.
metrics.accuracy_score(prediction1, test_Y))
-> 예측한 결과(prediction1)와 실제값(test_Y)를 비교해 정확도를 계산하라. 정확도 계산 함수는 metrics 패키지의 accuracy_score() 함수다. (metrics.accuracy_score(prediction1, test_Y))
캐글러의 radial SVM 정확도는 83.6%로 나보다 높았다..
나이 결측치 대체 방법을 다르게 한 결과가 썩 좋지 않을 수도 있겠다는 생각이 들기 시작했다.
하지만 아직 더 적용할 수 있는 분류 알고리즘이 많이 남아있으니... 계속 적용해보자..!
4) Linear SVM
#Linear SVM
model = svm.SVC(kernel = 'linear', C = 0.1, gamma = 0.1)
model.fit(train_X, train_Y)
prediction2 = model.predict(test_X)
print('Accuracy for linear SVM is', metrics.accuracy_score(prediction2, test_Y))
캐글러의 Linear-SVM의 정확도는 81.7%로 약간의 차이가 있었지만, 정확도는 여전히 캐글러가 더 높았다.
5) Logistic Regression
#Linear SVM
model = LogisticRegression()
model.fit(train_X, train_Y)
prediction3 = model.predict(test_X)
print('Accuracy for linear Logistic Regression is', metrics.accuracy_score(prediction3, test_Y))
캐글러의 결과는 81.7%
6) Decision Tree
#Decision Tree
model = DecisionTreeClassifier()
model.fit(train_X, train_Y)
prediction4 = model.predict(test_X)
print('Accuracy for Decision Tree is', metrics.accuracy_score(prediction4, test_Y))
캐글러의 결과는 79.85%였는데 트리에서는 더 좋은 결과를 보였다..!
그렇다면 보편적으로 가장 많이 사용하는 랜덤포레스트의 결과도 더 좋을 수 있겠다는 기대감이 들기 시작했다.
7) KNN
#KNN
model = KNeighborsClassifier()
model.fit(train_X, train_Y)
prediction5 = model.predict(test_X)
print('Accuracy for KNN is', metrics.accuracy_score(prediction5, test_Y))
캐글러는 83.2%로 내 결과가 좀 더 좋았다!
KNN은 n_neighbors이라는 튜닝 파라미터에 따라 정확도 차이가 조금씩 나기 때문에 파라미터를 직접 대입해 결과를 비교하는 것이 좋아보였다.
a_index = list(range(1, 11))
a = pd.Series()
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in list(range(1, 11)):
model = KNeighborsClassifier(n_neighbors = i)
model.fit(train_X, train_Y)
prediction = model.predict(test_X)
a = a.append(pd.Series(metrics.accuracy_score(prediction, test_Y)))
plt.plot(a_index, a)
plt.xticks(x)
fig = plt.gcf()
fig.set_size_inches(12, 6)
plt.show()
print('Accuracies for different values of n are:', a.values, 'with the max value as', a.values.max())
a_index = list(range(1, 11))
-> 1부터 10까지 적힌 리스트를 a_index로 저장
a = pd.Series()
-> 시리즈형으로 저장할 a 생성
x는 0에서 10까지 적힌 리스트형
for i in list(range(1, 11)):
-> 1부터 10까지 반복 시행
model = KNeighborsClassifier(n_neighbors = i)
-> KNN의 n_neighbors 파라미터를 1부터 10까지 10번 반복해서 모델을 생성한다.
model.fit(train_X, train_Y)
-> 훈련데이터로 model을 훈련
prediction = model.predict(test_X)
-> 훈련시킨 model이라는 모델에 test의 feature로 target 예측해서 그 결과를 prediction에 저장
a = a.append(pd.Series(metics.accuracy_score(prediction, test_Y)))
-> 예측결과인 prediction과 실제값인 test_Y를 비교해 정확도를 구함 (metrics.accuracy_score(prediction, test_Y))
그 정확도를 아까 만든 a라는 시리즈형 데이터에 차곡차곡 시리즈형으로 저장 (a = a.append(pd.Series(~~~))
plt.plot(a_index, a)
-> a_index라는 인덱스값에 정확도를 구한 시리즈형 데이터 a라는 데이터로 플롯을 그릴거야
plt.xticks(x)
-> x축은 0부터 10으로 표시
fig = plt.gcf()
-> 플롯 하나만 출력할때 pyplot의 .gcf() 함수 사용
fig.set_size_inches(12, 6)
-> 플롯 사이즈는 12*6
plt.show()
-> 그렇게 그린 그래프를 보여다오.
print('Accuracies for different values of n are:', a.values, 'with the max value as', a.values.max())
-> 아, 그리고 하나만 더 출력해줘. 정확도 전체랑 그 중에 제일 높은 값을 좀 출력해줘.
8) Gaussian Naive Bayes
#Gaussian NB
model = GaussianNB()
model.fit(train_X, train_Y)
prediction6 = model.predict(test_X)
print('Accuracy for NaiveBayes is', metrics.accuracy_score(prediction6, test_Y))
캐글러의 결과는 81.3%로 높았다.
9) Random Forests
#Random Forests
model = RandomForestClassifier()
model.fit(train_X, train_Y)
prediction7 = model.predict(test_X)
print('Accuracy for Random Forests is', metrics.accuracy_score(prediction7, test_Y))
기대했던 랜덤포레스트의 정확도가 고작 80.2%로 나왔다.
혹시 몰라서 n_estimators = 50으로 설정하고 다시 훈련시켰다.
다행히도 더 높아졌다.
근데 캐글러가 n_estimators = 100으로 했을 때의 정확도와 완전히 동일하게 나왔다.
신기하네...
모델 정확도가 높다고해서 바로 채택할 수는 없다.
왜냐면 train, test데이터를 나눈 것에 따라 수치가 다르기 때문이다.
이 문제를 해소하기 위해 Cross Validation(교차검증)을 실시한다.
2. Cross Validation
그동안 교차검증을 적용하고 싶은데 분류 알고리즘에 교차검증을 적용하는 법을 몰라서 많이 헤맸었다.
이번에 제대로 배워보자..!
#Cross Validation
from sklearn.model_selection import KFold, cross_val_score, cross_val_predict
kfold = KFold(n_splits = 10, random_state = 22)
xyz = []
accuracy = []
std = []
classifiers = ['Linear SVM', 'Radial SVM', 'Logistic Regression',
'KNN', 'Decision Tree', 'Naive Bayes', 'Random Forest']
models = [svm.SVC(kernel = 'linear'), svm.SVC(kernel = 'rbf'), LogisticRegression(),
KNeighborsClassifier(n_neighbors = 5), DecisionTreeClassifier(),GaussianNB(),
RandomForestClassifier(n_estimators = 50)]
for i in models:
model = i
cv_result = cross_val_score(model, X, Y, cv = kfold, scoring = "accuracy")
cv_result = cv_result
xyz.append(cv_result.mean())
std.append(cv_result.std())
accuracy.append(cv_result)
new_models_dataframe2 = pd.DataFrame({'CV Mean': xyz, 'Std': std}, index = classifiers)
new_models_dataframe2
kfold = KFold(n_splits = 10, random_state = 22)
-> 10-Fold로 나눈다. 랜덤시드는 22
xyz = [], accuracy [], std = []
-> 반복문으로 저장할 리스트 세 개를 만듦
classifier = [~~]
-> 분류기 이름 리스트로 저장
models = [~~]
-> 모델링할 알고리즘 리스트 저장
for i in models:
-> models 리스트에 있는 알고리즘에 대해 반복문 시행 (총 7번 반복)
model = i
-> 훈련시킬 모델은 첫번째부터
cv_result = cross_val_score(model, X, Y, cv = kfold, scoring = "accuracy")
-> 교차검증하여 모델을 평가, model이라는 모델을 data의 feature인 X, data의 target인 Y로 훈련, cv = kfold, 평가 방법은 정확도
cv_result = cv_result
-> cv.result로 cv_result 저장 (이걸 굳이 왜 적어야되는지 이해를 못했음)
xyz.append(cv_result.mean())
-> 10-fold의 결과 cv_result의 평균 저장
std.append(cv_result.std())
-> 10-fold 결과의 표준편차 저장
accuracy.append(cv_result)
-> cv_result를 accuracy 리스트에 계속 저장
new_models_dataframe2 = pd.DataFrame({'CV Mean': xyz, 'Std': std}, index = classifiers)
-> new_modesl_dataframe2라는 새로운 데이터프레임을 만들거야 (new_models_dataframe2 = pd.DataFrame() )
딕셔너리 형식으루다가 아까 구한 각 모델의 교차검증 평균치랑 표준편차로, ( {'CV Mean': xyz, 'Std': std} )
그 데이터프레임의 인덱스는 아까 만든 classifiers로 할거야. (index = classifier)
plt.subplots(figsize = (12, 6))
box = pd.DataFrame(accuracy, index = [classifiers])
box.T.boxplot()
plt.subplots(figsize = (12, 6))
-> 12*6의 레이아웃을 만들어라.
box = pd.DataFrame(accuracy, index = [classifiers])
-> box라는 이름의 데이터프레임을 만들건데 accuracy랑 classifiers리스트로 만들어라.
box.T.boxplot()
-> box라는 데이터프레임을 전치시켜서 박스플롯을 그려달라.
new_models_dataframe2['CV Mean'].plot.barh(width = 0.8)
plt.title('Average CV Mean Accuracy')
fig = plt.gcf()
fig.set_size_inches(8, 5)
plt.show()
new_models_dataframe2['CV Mean'].plot.barh(width = 0.8)
-> new_models_dataframe2 데이터프레임의 'CV Mean' 칼럼으로 누운 막대 그래프를 그려라.
new_models_datafram2['CV Mean'].plot.barh()
막대의 너비는 0.8 (width = 0.8)
교차검증을 통한 정확도까지 확인했을 때, 좋은 결과를 보인 모델은 랜덤포레스트, Radial SVM에 의사결정나무 정도까지 더할 수 있겠다.
하지만 교차검증만으로도 여전히 좋은 모델을 만들었다고 하기는 어렵다.
만약 예측 결과가 생존에서는 정확한데 사망에서만 잘못된 예측이 잔뜩 나온 경우, 아무리 정확도가 높아도 좋은 모델이라고 할 수 없다.
이를 확인하기 위해 F1점수로 평가하기도 하는데, 그 점수를 쓰기 전에 먼저 confusion matrix(혼동행렬)로 예측결과를 확인한다.
3. Confusion Matrix(혼동행렬)
f, ax = plt.subplots(3, 3, figsize = (12, 10))
y_pred = cross_val_predict(svm.SVC(kernel = 'rbf'), X, Y, cv = 10)
sns.heatmap(confusion_matrix(Y, y_pred), ax = ax[0, 0], annot = True, fmt = '2.0f')
ax[0, 0].set_title('Matrix for rbf-SVM')
y_pred = cross_val_predict(svm.SVC(kernel = 'linear'), X, Y, cv = 10)
sns.heatmap(confusion_matrix(Y, y_pred), ax = ax[0, 1], annot = True, fmt = '2.0f')
ax[0, 1].set_title('Matix for linear-SVM')
y_pred = cross_val_predict(KNeighborsClassifier(n_neighbors = 5), X, Y, cv = 10)
sns.heatmap(confusion_matrix(Y, y_pred), ax = ax[0, 2], annot = True, fmt = '2.0f')
ax[0, 2].set_title('Matrix for KNN')
y_pred = cross_val_predict(RandomForestClassifier(n_estimators = 50), X, Y, cv = 10)
sns.heatmap(confusion_matrix(Y, y_pred), ax = ax[1, 0], annot = True, fmt = '2.0f')
ax[1, 0].set_title('Matix for RandomForests')
y_pred = cross_val_predict(LogisticRegression(), X, Y, cv = 10)
sns.heatmap(confusion_matrix(Y, y_pred), ax = ax[1, 1], annot = True, fmt = '2.0f')
ax[1, 1].set_title('Matrix for Logistic Regresssion')
y_pred = cross_val_predict(DecisionTreeClassifier(), X, Y, cv = 10)
sns.heatmap(confusion_matrix(Y, y_pred), ax = ax[1, 2], annot = True, fmt = '2.0f')
ax[1, 2].set_title('Matrix for DecisionTree')
y_pred = cross_val_predict(GaussianNB(), X, Y, cv = 10)
sns.heatmap(confusion_matrix(Y, y_pred), ax = ax[2, 0], annot = True, fmt = '2.0f')
ax[2, 0].set_title('Matrix for Naive Bayes')
plt.subplots_adjust(hspace = 0.2, wspace = 0.2)
plt.show()
y_pred = cross_val_predict(RandomForestClassifier(n_estimators = 50), X, Y, cv = 10)
-> n = 50인 랜덤포레스트 모델을 data의 feature인 X와 target인 Y로 훈련시키는데 10-fold 교차검증을 통해 예측한 값을 y_pred에 저장해라.
sns.heatmap(confusion_matrix(Y, y_pred), ax = ax[1, 0], annot = True, fmt = '2.0f')
-> 실제값인 Y와 예측값인 y_pred로 혼동행렬을 만들어서 레이아웃 중 2행 1열에 그려라.
( sns.heatmap(confusion_matrix(Y, y_pred), ax = ax[1, 0] )
각 사각형에 해당하는 수치를 표시해라. ( annot = True)
annot으로 표현하는 숫자는 100의자리까지 표현 ( fmt = '2.0f')
혼동행렬 해석,
1행 1열에 있는 rbf-SVM를 대표로 설명하자면.
1) 정확도는 (490+247)/891 = 82.7%
2) 오류는 각각 59개, 95개이다. 죽은 사람을 살았다고 예측한 오류를 95개로 더 많이 범했다.
4. Hyperparameter Tuning
1) Tuning for SVM
from sklearn.model_selection import GridSearchCV
C = [0.05, 0.1, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
gamma = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
kernel = ['rbf', 'linear']
hyper = {'kernel': kernel, 'C': C, 'gamma': gamma}
gd = GridSearchCV(estimator = svm.SVC(), param_grid = hyper, verbose = True)
gd.fit(X, Y)
print(gd.best_score_)
print(gd.best_estimator_)
SVC의 하이퍼파라미터인 C와 gamma 중 최적의 파라미터를 찾기 위해서 그리드서치CV를 이용한다.
GridSearchCV를 사용하면 최적의 파라미터를 찾음과 동시에 교차검증도 가능해서 편리하다.
C = [~~~], gamma = [~~~]
먼저, C와 gamma에 사용할 값들을 각각 C와 gamma라는 리스트로 정리해준다.
kernel = ['rbf', 'linear']
SVM의 커널 linear과 radial도 kernel이라는 리스트로 정리해준다.
hyper = {'kernel': kernel, 'C': C, 'gamma': gamma}
그리고 커널과 C, gamma를 딕셔너리형으로 묶어준다.
※ 그리드서치CV에 사용할 파라미터 후보들은 꼭 딕셔너리형으로 지정해주어야 한다!
gd = GridSearchCV(estimator = svm.SVC(), param_grid = hyper, verbose = True)
그리드서치CV를 진행하는데 gd라고 저장한다. gd = GridSearchCV()
옵션 1. 사용할 알고리즘은 SVM ( estimator = svm.SVC() )
옵션 2. 사용할 파라미터 그리드는 hyper ( parma_grid = hyper) )
옵션3. verbose 옵션은 그리드서치CV에서 iteration마다 수행 결과를 출력하는 옵션이다.
verbose = 0 (verbose = False) 이면 메시지 출력 안 함
verbose = 1 이면 간단한 메시지 출력
verbose = 2 는 하이퍼파라미터별 메시지 출력이다.
verbose = True는 verbose = 1이랑 같은 의미다.
gd.fit(X, Y)
-> gd 모델을 X, Y로 훈련한다.
print(gd.best_score_)
gd모델에서 가장 높은 정확도를 출력
print(gd.best_estimator_)
gd모델에서 가장 높은 정확도를 보인 하이퍼파라미터 조합을 출력
그런데 커널은 출력되지 않았다..
커널을 보려고 verbose = 2로 했다가 너무 출력하는 결과가 많아서 취소하고, verbose = 1로 다시 해보았지만 여전히 커널이 출력되지 않았다.
2) Random Forest Tuning
n_estimators = range(50, 1000, 50)
hyper = {'n_estimators': n_estimators}
gd = GridSearchCV(estimator = RandomForestClassifier(random_state = 0), param_grid = hyper, verbose = 1)
gd.fit(X, Y)
print(gd.best_score_)
print(gd.best_estimator_)
n_estimators = range(50, 1000, 50)
랜덤포레스트의 n_estimators 튜닝파라미터를 50부터 1000까지 50간격으로 수행하라고 했다.
후보는 19개인데 시간은 1.7분이나 걸렸다.
SVM은 240개의 후보군을 돌리는데 37초가 걸린데 반해 수행시간이 아주 길었다.
SVM은 C = 0.9, gamma = 0.1일 때 82.9%의 정확도를 보였고, 랜덤포레스트는 n_estimators = 200일 때, 81.6%의 정확도를 보였다.
3. Ensembling
앙상블기법은 정확도, 성능을 향상시키기 위한 좋은 방법이다.
단순한 모델 여러가지를 조합해서 파워풀한 모델로 만드는 것이다.
대표적인 앙상블 기법 3가지가 있다.
1) Voting Classifier
2) Bagging
3) Boosting
1) Voting Classifier
Voting은 단순한 여러 머신러닝 기법을 합쳐서 예측 성능을 향상시키는 가장 단순한 방법이다.
모든 submodel들의 예측을 기반으로 평균 예측 결과를 만든다.
from sklearn.ensemble import VotingClassifier
ensemble_lin_rbf = VotingClassifier(
estimators = [('KNN', KNeighborsClassifier(n_neighbors = 10)),
('RBF', svm.SVC(probability = True, kernel = 'rbf', C = 0.5, gamma = 0.1)),
('RFor', RandomForestClassifier(n_estimators = 500, random_state = 0)),
('LR', LogisticRegression(C = 0.05)),
('DT', DecisionTreeClassifier(random_state = 0)),
('NB', GaussianNB()),
('SVM', svm.SVC(kernel = 'linear', probability = True))],
voting = 'soft').fit(train_X, train_Y)
print('The accuracy for ensembled model is:', ensemble_lin_rbf.score(test_X, test_Y))
cross = cross_val_score(ensemble_lin_rbf, X, Y, cv = 10, scoring = 'accuracy')
print('The cross validated score is', cross.mean())
VotingClassifier을 쓰려면 sklearn.ensemble에서 불러와야한다.
ensemble_lin_rbf = VotingClassifier(~~~)
-> VotingClassifier을 쓴 모델을 ensemble_lin_rbf라는 이름으로 저장할 것이다.
VotingClassifier(estimators = [('KNN', KNeighborsClassifier(n_neighbors = 10)), ~~~], voting = 'soft')
-> Voting에 사용할 알고리즘은 리스트 형태로 쭉 나열한다. VotingClassifier(estimators = [])
리스트 안에 알고리즘은 ('알고리즘명', 알고리즘()) 이런 형식으로 적어야한다.
옵션1. voting = 'soft' 옵션은 예측한 확률이 가장 높은 클래스를 선택
voting = 'hard' 옵션은 가장 많은 표를 얻은 결과를 선택
VotingClassifier().fit(train_X, train_Y)
-> VotingClassifier() 모델을 train_X와 train_Y로 훈련
print('The accuracy for ensembled model is:', ensemble_lin_rbf.score(test_X, test_Y))
-> Voting 앙상블기법의 성능 평가
cross = cross_val_score(ensemble_lin_rbf, X, Y, cv = 10, scoring = 'accuracy')
-> ensemble_lin_rbf 모델에 data의 feature과 target을 이용해서 10-fold CV 시행, 방식은 정확도
그것을 cross라는 모델명으로 저장
print('The cross validated score is', cross.mean())
-> 교차검증을 실행한 결과의 평균을 계산
2) Bagging
배깅은 앙상블기법 중 가장 일반적인 방식으로, 서로 비슷한 분류기들을 이용한다.
배깅은 분산이 큰 모델에서 가장 잘 작동하기 때문에 n이 작을 때의 KNN이나, 의사결정 나무, 랜덤포레스트에 적당하다.
from sklearn.ensemble import BaggingClassifier
model = BaggingClassifier(base_estimator = KNeighborsClassifier(n_neighbors = 3), random_state = 0,
n_estimators = 700)
model.fit(train_X, train_Y)
prediction = model.predict(test_X)
print('The accuracy for bagged KNN is:', metrics.accuracy_score(prediction, test_Y))
result = cross_val_score(model, X, Y, cv = 10, scoring = 'accuracy')
print('The cross validated score foe bagged KNN is:', result.mean())
model = BaggingClassifier(base_estimator = KNeighborsClassifier(n_neighbors = 3), random_state = 0, n_estimators = 700)
BaggingClassifier()를 사용한 모델을 model로 저장한다. model = BaggingClassifier()
KNN의 negihbors는 3으로 정한다.
random_state = 0 -> 배깅의 랜덤시드는 0
n_estimators = 700 -> 배깅의 n_estimators = 700
[1] Bagged KNN
[2] Bagged DecisionTree
model = BaggingClassifier(base_estimator = DecisionTreeClassifier(), random_state = 0, n_estimators = 100)
model.fit(train_X, train_Y)
prediction = model.predict(test_X)
print('The accuracy for bagged Decision Tree is:', metrics.accuracy_score(prediction, test_Y))
result = cross_val_score(model, X, Y, cv = 10, scoring = 'accuracy')
print('The cross validated score for bagged Decision Tree is:', result.mean())
의사결정나무에 대한 배깅을 시행
3) Boosting
마지막으로 살펴볼 앙상블 기법은 Boosting이다.
부스팅은 분류기의 연속적인 학습을 이용하는 기법으로 weak 모델을 단계적으로 향상시켜 강화한다.
[1] AdaBoost
AdaBoost는 Adaptive Boosting의 줄임말이다.
from sklearn.ensemble import AdaBoostClassifier
ada = AdaBoostClassifier(n_estimators = 200, random_state = 0, learning_rate = 0.1)
result = cross_val_score(ada, X, Y, cv = 10, scoring = 'accuracy')
print('The cross validated score for AdaBoost is:', result.mean())
ada = AgaBoostClassifier(n_estimators = 200, random_state = 0, learning_rate = 0.1)
-> ada라는 이름으로 AdaBoost 모델을 저장한다. ada = AdaBoostClassifier()
n_estimators = 200, 랜덤시드는 0 (random_state = 0)로 지정,
learning_rate = 0.1 -> 학습할 양을 조절해준다. 일반적으로는 learning_rate = 1이라고 한다.
[2] Stochastic Gradient Boosting
from sklearn.ensemble import GradientBoostingClassifier
grad = GradientBoostingClassifier(n_estimators = 500, random_state = 0, learning_rate = 0.1)
result = cross_val_score(grad, X, Y, cv = 10, scoring = 'accuracy')
print('The cross validated score for Gradient Boosting is:', result.mean())
[3] XGBoost
import xgboost as xg
xgboost = xg.XGBClassifier(n_estimators = 900, learning_rate = 0.1)
result = cross_val_score(xgboost, X, Y, cv = 10, scoring = 'accuracy')
print('The cross validated score for XGBoost is:', result.mean())
xgboost는 싸이킷런에 없어서 따로 라이브러리를 설치해야한다.
근데 버전 문제때문인지 라이브러리 설치과정에서 오류가 몇 번 있었다.
해결하기 위해서 아나콘다프롬프트를 킨 다음에, 아래와 같이 입력했다.
conda install -c anaconda py-xgboost
여기서 설치 중 오류가 발생했는데 오류가 발생했음에도 다시 pip install xgboost를 시도하니 설치가 됐다.
Boosting 기법 세 가지 중에서는 AdaBoost의 정확도가 가장 높았으므로 Adaboost에 대해 parameter tuning을 진행하자.
[4] AdaBoost의 hyperparameter tuning
n_estimators = list(range(100, 1100, 100))
learn_rate = [0.05, 0.1, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
hyper = {'n_estimators': n_estimators, 'learning_rate': learn_rate}
gd = GridSearchCV(estimator = AdaBoostClassifier(), param_grid = hyper, verbose = 1)
gd.fit(X, Y)
print(gd.best_score_)
print(gd.best_estimator_)
adaboost의 하이퍼파라미터인 n_estimators와 learning_rate에 대해서 후보군을 정해주고,
GridSearchCV에 사용할 딕셔너리형으로 저장한다.
-> hyper = {'n_estimators': n_estimators, 'learning_rate': learn_rate}
gd = GridSearchCV(estimator = AdaBoostClassifier(), param_grid = hyper, verbose = 1)
-> 그리드서치를 AdaBoost모델로 진행하고 gd라는 모델명으로 저장
( gd = GridSearchCV(estimator = AdaBoostClassifier() )
하이퍼파라미터 후보군 지정 param_grid = hyper
결과는 간단하게 출력 ( verbose = 1 )
learning_rate = 0.1, n_estimators = 100일 때, 83.05%로 최대 정확도가 나왔다.
4) 최고 성능 모델의 혼동행렬 확인
앙상블기법 중에서는 AdaBoost가 가장 좋은 성능을 보였기때문에 이에 대한 혼동행렬을 확인해보자.
ada = AdaBoostClassifier(n_estimators = 100, random_state = 0, learning_rate = 0.1)
result = cross_val_predict(ada, X, Y, cv = 10)
sns.heatmap(confusion_matrix(Y, result), cmap = 'winter', annot = True, fmt = '2.0f')
plt.show()
ada = AdaBoostClassifier(n_estimators = 200, random_state = 0, learning_rate = 0.05)
-> 가장 좋은 정확도를 보인 최적의 parameter 조합
result = cross_val_predict(ada, X, Y, cv = 10)
-> 최적의 AdaBoost 모델에 10-fold CV를 적용
sns.heatmap(confusion_matrix(Y, result), cmap = 'winter', annot = True, fmt = '2.0f')
-> 실제값 Y와 예측값인 result로 혼동행렬을 구성해서 그걸 히트맵으로 ( sns.heatmap(confusion_matrix(Y, result)) )
이번엔 테마를 winter로 ( cmap = 'winter' )
빈도수를 표현 ( annot = True )
백의자리까지 표현 ( fmt = '2.0f' )
4. Feature Importance
Feature Importance는 이번 타이타닉 데이터 분석의 마지막 단계로 중요한 특성을 파악하기 위한 과정이다.
f, ax = plt.subplots(2, 2, figsize = (15, 12))
model = RandomForestClassifier(n_estimators = 200, random_state = 0)
model.fit(X, Y)
pd.Series(model.feature_importances_,
X.columns).sort_values(ascending = True).plot.barh(width = 0.8, ax = ax[0, 0])
ax[0, 0].set_title('Feature Importancein RandomForests')
model = AdaBoostClassifier(n_estimators = 100, learning_rate = 0.1, random_state = 0)
model.fit(X, Y)
pd.Series(model.feature_importances_,
X.columns).sort_values(ascending = True).plot.barh(width = 0.8, ax = ax[0, 1], color = '#ddff11')
ax[0, 1].set_title('Feature Importance in AdaBoost')
model = GradientBoostingClassifier(n_estimators = 500, learning_rate = 0.1, random_state = 0)
model.fit(X, Y)
pd.Series(model.feature_importances_,
X.columns).sort_values(ascending = True).plot.barh(width = 0.8, ax = ax[1, 0], cmap = 'RdYlGn_r')
ax[1, 0].set_title('Feature Importance in Gradient Boosting')
model = xg.XGBClassifier(n_estimators = 900, learning_rate = 0.1)
model.fit(X, Y)
pd.Series(model.feature_importances_,
X.columns).sort_values(ascending = True).plot.barh(width = 0.8, ax = ax[1, 1], color = '#FD0F00')
ax[1, 1].set_title('Feature Importance in XgBoost')
plt.show()
feature importance를 보기 위해서는 먼저 모델을 만들어준다. model = RandomForestClassifier()
만들어준 모델을 model이라고 명명하고 훈련을 시킨다. model.fit(X, Y)
model.feature_importances_ 로 중요한 특성을 확인할 수 있다.
pd.Series(model.feature_importances_, X.colums)
-> 만든 모델의 중요 특성을 시리즈형으로 저장한다. 인덱스를 X.columns로 지정한다.
pd.Series(~~).sort_values(ascending = True)
-> 그 시리즈형으로 저장한 중요 특성을 오름차순으로 정렬한다.
----------------------------> 오름차순 정렬을 하기위한 .sort_values(ascending = True) 함수를 배웠다.
pd.Series(~~).sort_value(ascending = True).plot.barh(width = 0.8, ax = ax[0, 0])
-> 오름차순으로 정렬한 시리즈형을 누운 막대그래프로 그린다. ( .plot.barh() )
막대 너비는 0.8로 지정 ( width = 0.8 )
레이아웃의 1행 1열에 그린다. ( ax = ax[0, 0] )
그래프 관찰 결과,
1) Initial, Pclass, Family_Size, Fare_cat이 공통적으로 중요한 변수로 나왔다.
2) 성별이 중요한 변수일 것이라 예상했지만 랜덤포레스트를 제외하고는 중요한 특성으로 꼽지않은 점이 충격적이었다.
아마도, 성별 대신 성별의 정보를 포함하면서 더 많은 정보를 전달하는 Initial 특성때문인 것 같다.
이전에 특성끼리의 상관관계를 봤을 때, 성별과 이니셜의 상관관계가 높았다는 점도 한 몫하는 듯 한다.
3) Pclass, Fare_cat 역시 높은 상관관계가 있고, Family_Size와 SibSp, Parch, Alone의 상관관계가 있어 비슷한 결과가 나온듯 하다.
이렇게 타이타닉 생존자 예측 모델링과 중요 특성까지 선별해보았다.
그동안 헷갈려서 적용하지 못했단 교차검증이나, Feature Importance 선별 등을 확실히 배울 수 있었고,
이외에도 여러 패키지를 적용하는 법이나 모델링을 좀 더 효과적으로 하는 법 등을 배울 수 있어 유익한 공부가 되었다.
다음에도 이런 캐글 데이터를 다룰 때 이번에 공부한 내용을 아주 많이 적용할 수 있을 것 같아 기대된다.
아직도 앙상블기법에 대해 이해가 부족하다는 것을 다시 느껴서 더 열심히 공부해야겠다는 생각도 들었다.
계속 데이터를 다루며 실력을 키워야겠다.
'연습장' 카테고리의 다른 글
DP로 생각하기 - LIS 문제와 그 응용 (0) | 2024.05.21 |
---|---|
DP(동적 계획법)에 대한 이해 (1) | 2024.05.16 |
[Kaggle] 캐글 상위권 코드 보고 공부하는 타이타닉 예제 심화 Feature Engineering (나이대, 요금대, 가족으로 변수 묶기/문자형 자료 변환/칼럼 삭제) (0) | 2020.11.11 |
[Kaggle] 캐글 상위권 코드 보고 공부하는 타이타닉 예제 심화 EDA 2 (이름 특성에서 인사이트 얻기, 승선장, 가족구성원 수, 요금 특성 분석) (0) | 2020.11.11 |
[Kaggle] 캐글 상위권 코드 보고 공부하는 타이타닉 예제 심화 EDA 1 (성별, 등급, 나이 특성 확인) (0) | 2020.11.11 |