타이타닉 분석3. modeling, validation, testing
In [1]:

# 캡쳐 사진 및 글작성에 대한 도움 출저 : 유튜브 - 허민석님


#-*- coding: utf-8 -*-# 블로그용 html조절from IPython.core.display import display, HTMLdisplay(HTML("<style> .container{width:90% !important;}</style>"))
In [1]:
import pandas as pdimport matplotlib.pyplot as plt%matplotlib inlineimport seaborn as snssns.set() #시본을 default plot으로 지정한다# label칼럼은 수동으로 적고, 행인덱싱, 이후, 행인덱싱 순서대로 합쳐진 df의 index명도 지정해줘야함.def bar_chart(feature):    #label 칼럼 수동으로 종류별 행인덱싱    survived = train.loc[ train['Survived'] == 1,: ][feature].value_counts()    dead = train.loc[ train['Survived'] == 0,: ][feature].value_counts()    df = pd.DataFrame([survived, dead])    #label 칼럼의 종류별로 합쳐진 df의 index 수동으로 순서대로 바꿔주기.    df.index = [ 'Survived', 'Dead']        print(df.head())    df.plot(kind='bar', stacked = True, figsize =(10,5))    
In [48]:
import pickletrain_data= pickle.load(open('fe_train.p', 'rb'))target= pickle.load(open('fe_target.p', 'rb'))test= pickle.load(open('test.p', 'rb'))

1. Modeling

In [49]:
train_data.head()
Out[49]:
Pclass Sex Age Fare Cabin Embarked Title FamilySize
0 3 0 1.0 0.0 2.0 0 0 0.4
1 1 1 3.0 2.0 0.8 1 2 0.4
2 3 1 1.0 0.0 2.0 0 1 0.0
3 1 1 2.0 2.0 0.8 0 2 0.4
4 3 0 2.0 0.0 2.0 0 0 0.0
In [50]:
train_data.info()
<class 'pandas.core.frame.DataFrame'>RangeIndex: 891 entries, 0 to 890Data columns (total 8 columns):Pclass        891 non-null int64Sex           891 non-null int64Age           891 non-null float64Fare          891 non-null float64Cabin         891 non-null float64Embarked      891 non-null int64Title         891 non-null int64FamilySize    891 non-null float64dtypes: float64(4), int64(4)memory usage: 55.8 KB

1.1 사이킷런(sklearn)에 있는 Classifier import하기

In [51]:
#kNNfrom sklearn.neighbors import KNeighborsClassifier#Decision Treefrom sklearn.tree import DecisionTreeClassifier#Random Forestfrom sklearn.ensemble import RandomForestClassifier#나이브 베이즈from sklearn.naive_bayes import GaussianNB# 서포터 벡터 머신from sklearn.svm import SVCimport numpy as np # np.mean 평균 등을 계산

1.2 사이킷런에 있는 K-fold Cross validation import하기

In [75]:
from sklearn.model_selection import KFoldfrom sklearn.model_selection import  cross_val_score#train 데이터를 10개로 등분 낼 예정, shuffle은 10등분하기 전 전체데이터를 한번섞는다. 그 이후 10개 쪼개는 과정에서는 shuffle안한다.k_fold = KFold(n_splits = 10, shuffle = True, random_state = 0)

2. Classifier로 분류하기

2-1. kNN Classifier

In [53]:
#  k=13 개의 네이버를 사용한다.clf = KNeighborsClassifier(n_neighbors= 13 )scoring = 'accuracy'#cross_val_score에는 #1 분류기의 종류, 2 train, 3 label, 4cv= cross_validation의 종류, 5 ?? , 6. 정확도 등 표시할 것#cross_val_score()의 반환결과는 cv의 종류에 지정해준 splits 개수대로 정확도가 나온다.score = cross_val_score(clf, train_data, target, cv=k_fold, n_jobs=1, scoring=scoring)print(score)
[0.82222222 0.76404494 0.80898876 0.83146067 0.87640449 0.82022472 0.85393258 0.79775281 0.84269663 0.84269663]
In [54]:
# 10개의 정확도 평균내기 ( 2번째 인자는 소수점 몇째짜리까지 표시되도록 반올림 할 것인가! )round(np.mean(score) * 100, 2)
Out[54]:
82.6

2-2. Decision Tree

  • kNN에서 했던 것에서 분류기만 바꿔준다.
In [55]:
clf = DecisionTreeClassifier()scoring = 'accuracy'score = cross_val_score(clf, train_data, target, cv=k_fold, n_jobs=1, scoring=scoring)print(score)
[0.76666667 0.80898876 0.7752809  0.76404494 0.8988764  0.76404494 0.83146067 0.82022472 0.75280899 0.79775281]
In [56]:
round(np.mean(score) * 100, 2)
Out[56]:
79.8

2-3. Random Forest

In [57]:
#랜덤포레스트의 tree수를 지정해준다. 13개clf = RandomForestClassifier(n_estimators=13)scoring = 'accuracy'score = cross_val_score(clf, train_data, target, cv=k_fold, n_jobs=1, scoring=scoring)print(score)
[0.8        0.83146067 0.82022472 0.79775281 0.86516854 0.80898876 0.80898876 0.82022472 0.76404494 0.79775281]
In [58]:
round(np.mean(score) * 100, 2)
Out[58]:
81.15

2-4. Naive Bayes

In [59]:
clf = GaussianNB()scoring = 'accuracy'score = cross_val_score(clf, train_data, target, cv=k_fold, n_jobs=1, scoring=scoring)print(score)
[0.85555556 0.73033708 0.75280899 0.75280899 0.70786517 0.80898876 0.76404494 0.80898876 0.86516854 0.83146067]
In [60]:
round(np.mean(score) * 100, 2)
Out[60]:
78.78

2-5. SVM

In [61]:
clf = SVC()scoring = 'accuracy'score = cross_val_score(clf, train_data, target, cv=k_fold, n_jobs=1, scoring=scoring)print(score)
[0.83333333 0.80898876 0.83146067 0.82022472 0.84269663 0.82022472 0.84269663 0.85393258 0.83146067 0.86516854]
In [62]:
round(np.mean(score) * 100, 2)
Out[62]:
83.5

SVM이 가장 큰 score를 내었으니, SVM을 분류기로 채택하고 testing한다.

테스트 데이터에... NaN이 있다.. 처리해보자.

In [41]:
test.info()
<class 'pandas.core.frame.DataFrame'>RangeIndex: 418 entries, 0 to 417Data columns (total 9 columns):PassengerId    418 non-null int64Pclass         418 non-null int64Sex            418 non-null int64Age            332 non-null float64Fare           418 non-null float64Cabin          418 non-null float64Embarked       418 non-null int64Title          417 non-null float64FamilySize     418 non-null float64dtypes: float64(5), int64(4)memory usage: 29.5 KB
In [65]:
test['Age'].fillna ( test.groupby('Pclass')['Age'].transform('median') , inplace = True )
In [69]:
test['Title'].fillna ( test['Title'].mean(), inplace=True)
In [70]:
test.info()
<class 'pandas.core.frame.DataFrame'>RangeIndex: 418 entries, 0 to 417Data columns (total 9 columns):PassengerId    418 non-null int64Pclass         418 non-null int64Sex            418 non-null int64Age            418 non-null float64Fare           418 non-null float64Cabin          418 non-null float64Embarked       418 non-null int64Title          418 non-null float64FamilySize     418 non-null float64dtypes: float64(5), int64(4)memory usage: 29.5 KB

3. Testing

In [71]:
#SVM을 이용하여, train 데이터 학습시키기clf = SVC()clf.fit(train_data, target)# test데이터에서 PassengerId칼럼만 빼내기(필요없어서)test_data = test.drop('PassengerId', axis = 1).copy()# SVM을 이용하여 test데이터 예측하기prediction = clf.predict(test_data)
In [72]:
# prediction결과는 리스트로 test데이터 개수만큼 나온다.prediction
Out[72]:
array([0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1,       1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1,       1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1,       1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1,       1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,       0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0,       0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,       0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1,       1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,       0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0,       1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,       0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,       0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0,       0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1,       0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0,       1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0,       0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0,       1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1,       0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1],      dtype=int64)

4. prediction결과(단순리스트)를 df프레임 형태로 저장해보기

  • test데이터 원본에는 남아있던 PassengerId와 prediction을 딕셔너리로 만들어서 DataFrame에 담아준다
  • 이 때, prediction은 0or1으로 나타나는 Survived이므로, Survived로 키값(칼럼명)으로 지정해준다.
In [73]:
submission = pd.DataFrame({    'PassengerId' : test['PassengerId'],    'Survived' : prediction})#저장할 때, index=False를 주면, 불러올 때 이쁘게 불러와진다.# 반대로 그냥 정해놓고, 불러올 때 ignore_index=True를 줘도 된다.submission.to_csv('submission.csv', index=False)
In [74]:
submission = pd.read_csv('submission.csv')submission.head()
Out[74]:
PassengerId Survived
0 892 0
1 893 1
2 894 0
3 895 0
4 896 1

참고

k_fold = KFold(n_splits=10, shuffle=True, random_state=0) 에서요 "shuffle = True"로 하면 어떤 의미인가요? 혹시 매번 CV할때마다 Shuffle한다는 의미일까요? CV의 가장 주된 목적이 모든 데이터를 validation set으로 써서 accuracy variation을 줄인것으로 생각하면 CV로 쪼갤때 마다 Shuffle은 좀 아닌거 같은데요 ㅎㅎ 찾아봐도 그 의미가 잘 안나와서요. kfold 없이 그냥 cv = 10인거 계속 돌려도 같은 값이 나오네요 ㅎㅎ shuffle의미가 저에게 어렵습니다 ㅎㅎㅎ

seongmin lee 안녕하세요, shuffle=True할 경우, k개로 데이터를 나누기 전에 단 한번 데이터를 뒤섞게 됩니다. 10개의 데이터가 생성된 후 라운드마다 인덱스 1부터 10까지 검증데이터로 사용하게 되어있어요. 셔플링은 k의 수에 상관없이

생존자 예측 모델을 여러개 테스트 해서 SVM이 제일 우수하다라는 것을 알게 되었습니다.SVM 모델을 어떻게 이용하면 prediction과 실제결과가 나오는 비교할 수있나요? prediction이 지금 array인데 이걸 DF타입으로 바꿔서 train의 survived를 새로운 열로 붙이면 되는 걸까요?

아래 링크 가셔서 최하단 부분의 코드를 활용하시면 될 거 같습니다.https://github.com/minsuk-heo/wikibooks_python_ml/blob/master/jupyter_notebook/svm_%EB%86%8D%EA%B5%AC%EC%84%A0%EC%88%98_%ED%8F%AC%EC%A7%80%EC%85%98_%EC%98%88%EC%B8%A1_%EC%8B%A4%EC%8A%B5.ipynb

갑자기 너무 많은 질문을 드려 죄송합니다만 ㅎㅎㅎ KFold를 하는 이유가 seed 설정때문에 하는거죠? 그냥 cross_val_score(cv = 10)으로 해도 되는데 이러면 매번 값이 바뀌기 때문이죠? 그래서 cv = KFold로 설정하는거죠? 여기서 질문드립니다. 제가 최적화된 n_neighbor 값을 KNN모델에서 찾으려고 루프를 돌렸는데요, 뭐가 잘못되었는지 for문에서는 Kfold가 iterable하지 않다고 하네요... 이럴때 gridSearch를 해야하는지요? 두개 코드를 다 돌려보면 좀 결과가 다른데 이유가 무엇인지 좀 알 수 있을까요?

[knn Parameter 찾기]neighbors = np.arange(1, 502, 5)

kfold = KFold(n_splits=5, random_state=123)

score_list = []cv_score_list = []for n in neighbors: knn = KNeighborsClassifier(n_neighbors=n) knn.fit(X_train, y_train) score = knn.score(X_train, y_train) cv_score = cross_val_score(estimator=knn, scoring= 'accuracy', cv=5, X=X_train, y=y_train) score_list.append(score) cv_score_list.append(cv_score.mean())

[Gridsearch해서 찾기]kfold = KFold(n_splits=5, random_state= 123)neighbors = np.arange(1, 502, 5)grid_param = {'n_neighbors':neighbors}

knn = KNeighborsClassifier()grid = GridSearchCV(estimator=knn, param_grid = grid_param, cv= kfold, scoring='accuracy')grid_result = grid.fit(X_train, y_train)print(grid_result.bestscore)print(grid_result.bestparams)

cross_val_score(cv = 10) 은 kfold의 k=10과 동일합니다. http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.cross_val_score.html제가 kfold 를 쓴 별다른 이유는 없지만, kfold를 더욱 비디오에서 명시적으로 보여드릴 수 있어서 사용했어요.두번째 질문은 sklearn가 내부적으로 어떻게 작용하는 지 알아야 대답할 수 있을 것 같은데, 제가 거기까진 잘 모르겠네요. 제가 아는바로는 둘 다 stratified k-fold cross-validation를 사용하는 걸로 알고 있는데, 차이 나는 이유는 잘 모르겠습니다.


+ Recent posts