본문 바로가기

Programming/Machine Learning

Titanic데이터활용_DecisionTree_Ensemble

Machine Learning 과정

- 문제정의

- 데이터 수집

- 데이터 전처리 (인코딩,특성공학)

- 탐색적 데이터 분석 (시각화, 특성선택)

- 모델 선택 및 학습

- 하이퍼파라미터 튜닝 (교차검증,그리드서치)

- 모델 평가

import pandas as pd
import numpy as np

 

데이터 사전

- PassengerId : 탑승객 id

- Survived : 생존여부 (0 = 사망, 1 = 생존)

- Pclass : 티켓 클래스 (1등급, 2등급, 3등급)

- Name : 이름

- Sex : 성별 (male = 남성, female = 여성)

- Age : 나이

- SibSp : 형제/배우자의 수

- Parch : 부모/자녀 수

- Ticket : 티켓 번호

- Fare : 요금

- Cabin : 객실번호

- Embarked : 승선항 C = 쉘 부르그, Q = 퀸즈타운, S = 사우스 햄튼

 

Feature engineering

데이터로드

train과 test를 병합해서 사용

    # train,test 데이터 로드
    train = pd.read_csv('./data/train.csv')    
    test = pd.read_csv('./data/test.csv')

    # 생존여부를 별도로 분리
    # inplace 속성으로 drop결과를 바로 적용
    targets = train.Survived
    train.drop(['Survived'], axis = 1, inplace=True)
    
    # 두 개의 데이터 병합
    # ignore_index 속성으로 train,test의 인덱스를 순차적으로 만듬
    combined = train.append(test,ignore_index=True)
    
    # PassengerId는 삭제
    combined.drop(['PassengerId'], 1, inplace=True)
    combined
    
    combined.shape
    
    combined.head()

 

탑승객 호칭 처리

- Braund, Mr. Owen Harris

- Heikkinen, Miss. Laina

- Oliva y Ocana, Dona. Fermina (귀부인)

- Peter, Master. Michael J (도련님)

def split_title(x):
    return x.split(',')[1].split('.')[0].strip()
    
titles = train["Name"].apply(split_title).unique()
titles

 

몇 개의 타이틀로 정리

- Officer (장교)

- Royalty (귀족)

- Mr

- Mrs

- Miss

- Master

Title_Dictionary = {
    "Capt": "Officer",
    "Col": "Officer",
    "Major": "Officer",
    "Jonkheer": "Royalty",
    "Don": "Royalty",
    "Sir" : "Royalty",
    "Dr": "Officer",
    "Rev": "Officer",
    "the Countess":"Royalty",
    "Mme": "Mrs",
    "Mlle": "Miss",
    "Ms": "Mrs",
    "Mr" : "Mr",
    "Mrs" : "Mrs",
    "Miss" : "Miss",
    "Master" : "Master",
    "Lady" : "Royalty"
}

combined['Title'] = combined["Name"].apply(split_title)
#map함수를 통해 딕셔너리의 키 값과 시리즈의 인덱스 값이 같은 데이터를 찾아 변경
combined['Title'] = combined.Title.map(Title_Dictionary)

combined.head()

 

나이 처리

- 시각화를 위해 중간 값으로 단순히 처리했지만, 좀 더 세분화 해서 나이를 채워보자

- 성별,선실등급,호칭으로 묶어서 평균나이를 구해보자

# as_index 속성으로 그룹을 묶는 컬럼을 인덱스에서 제외하자
grouped_train = combined.iloc[:891].groupby(['Sex','Pclass','Title'],as_index = False)
grouped_median_train = grouped_train.median()
grouped_median_train = grouped_median_train[['Sex', 'Pclass', 'Title', 'Age']]
grouped_median_train
# 성별과 선실등급 그리고 호칭에 따라 평균 나이가 조금씩 다르다.

def fill_age(row):
    condition = (
            (grouped_median_train['Sex'] == row['Sex']) & 
            (grouped_median_train['Title'] == row['Title']) & 
            (grouped_median_train['Pclass'] == row['Pclass'])
        ) 
    if np.isnan(row['Age']): 
        return grouped_median_train[condition]['Age'].values[0]
    else :
        return row['Age']
        
combined['Age'] = combined.apply(fill_age, axis=1)

 

이름 처리

- 이름 특성 삭제

- 카테고리화 되어있는 호칭을 Model이 계산 할 수 있도록 one-hot-encoding

#이름 특성 삭제
combined.drop('Name', axis=1, inplace=True)

titles_dummies = pd.get_dummies(combined['Title'], prefix='Title')
titles_dummies.head()

combined = pd.concat([combined, titles_dummies], axis=1)
combined.drop('Title', axis=1, inplace=True)

combined.head()

 

요금 처리

combined.Fare.fillna(combined.Fare.mean(), inplace=True)

 

승선항 처리

- 결측치는 많은 사람들이 탑승한 S로 채운다

- encoding

combined.iloc[:891].Embarked.value_counts()

# 결측치 처리
combined.Embarked.fillna('S', inplace=True)
    
# one-hot-encoding
embarked_dummies = pd.get_dummies(combined['Embarked'], prefix='Embarked')
combined = pd.concat([combined, embarked_dummies], axis=1)

# 승선항 특성 삭제
combined.drop('Embarked', axis=1, inplace=True)

combined.head()

 

객실번호

- 결측치는 U(Uknown)로 대체

- 숫자를 제거한 맨 앞 글자로 변경

- encoding

# 결측치는 U로 대체
combined['Cabin'].fillna('U',inplace=True)

# Cabin의 첫 글자로 변경
combined['Cabin'] = combined['Cabin'].str[0]

# one-hot-encoding
cabin_dummies = pd.get_dummies(combined['Cabin'], prefix='Cabin')    
combined = pd.concat([combined, cabin_dummies], axis=1)

# Cabin 특성 삭제
combined.drop('Cabin', axis=1, inplace=True)

combined.head()

 

성별 처리

# 남성은 1 여성은 0으로 변경
combined['Sex'] = combined['Sex'].map({'male':1, 'female':0})

combined.head()

 

객실등급 처리

# one-hot-encoding
pclass_dummies = pd.get_dummies(combined['Pclass'], prefix="Pclass")
combined = pd.concat([combined, pclass_dummies],axis=1)
    
# 객실등급 특성 삭제
combined.drop('Pclass',axis=1,inplace=True)

combined.head()

 

티켓 처리

def cleanTicket(ticket):
    # .과/를 없애준다.
    ticket = ticket.replace('.', '')
    ticket = ticket.replace('/', '')
    # 공백 기준으로 자른다.
    ticket = ticket.split()
    print(ticket)
    # 자른 리스트의 각 항목의 양쪽 공백을 없애준다.
    ticket = map(lambda t : t.strip(), ticket)
    # 숫자가 아닌 것만 필터링해서 리스트로 만듬
    ticket = list(filter(lambda t : not t.isdigit(), ticket))
    if len(ticket) > 0:
        return ticket[0]
    else: 
        return 'XXX' #티켓 글자가 없으면 XXX로 표시
        
combined['Ticket'] = combined['Ticket'].map(cleanTicket)
tickets_dummies = pd.get_dummies(combined['Ticket'], prefix='Ticket')
combined = pd.concat([combined, tickets_dummies], axis=1)
combined.drop('Ticket', inplace=True, axis=1)

combined.head()

 

가족관련 특성 처리

- 부모,자녀,배우자,형제 모두 합친 특성을 새롭게 만듬

- 가족 숫자에 따라 1인, 소규모 가족, 대규모 가족으로 구분

# 본인을 포함하여 모든 가족수 특성 생성
combined['FamilySize'] = combined['Parch'] + combined['SibSp'] + 1

# map함수는 apply처럼 함수를 넣어서 사용가능
# lambda는 간단한 함수를 줄여서 쓰는 방식
combined['Singleton'] = combined['FamilySize'].map(lambda s: 1 if s == 1 else 0)
combined['SmallFamily'] = combined['FamilySize'].map(lambda s: 1 if 2 <= s <= 4 else 0)
combined['LargeFamily'] = combined['FamilySize'].map(lambda s: 1 if 5 <= s else 0)

combined.head()

 

모델링

X_train = combined.iloc[:891]
y_train = targets
X_test = combined.iloc[891:]

print(X_train.shape)
print(y_train.shape)
print(X_test.shape)

 

앙상블

from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import LinearSVC

knn_model = KNeighborsClassifier()
tree_model = DecisionTreeClassifier()
forest_model = RandomForestClassifier()

voting_model = VotingClassifier(
    estimators = [
        ('knn1', knn_model),
        ('tree1', tree_model),
        ('forest1', forest_model)
    ],
    voting='soft'
)

voting_model.fit(X_train,y_train)

pre = voting_model.predict(X_test)
pre

forest_model2 = RandomForestClassifier(n_estimators=1000, max_features=0.7, max_depth=5, min_samples_leaf=15, max_leaf_nodes=50)

from sklearn.model_selection import GridSearchCV

param_grid = {
    'max_depth' : [5, 10, 15, 20],
    'n_estimators' : [1000, 1500, 2000, 2500],
    'max_features' : [0.5, 0.7],
    'max_leaf_nodes' : [20, 50, 80]
}

grid = GridSearchCV(forest_model2,
                   param_grid,
                   cv=3)
                   
grid.fit(X_train, y_train)

print('best score : ', grid.best_score_)
print('best params : ', grid.best_params_)

final_forest_model = RandomForestClassifier(max_depth = 5, max_features= 0.5, max_leaf_nodes= 80, n_estimators= 1000 )

final_forest_model.fit(X_train, y_train)

pre = final_forest_model.predict(X_test)

result =pd.read_csv('data/gender_submission.csv')
result['Survived']=pre
result.to_csv('HHD_submission_0211_02.csv', index=False)

'Programming > Machine Learning' 카테고리의 다른 글

네이버 영화리뷰 감성분석  (0) 2020.02.17
Sentiment Analysis(영화리뷰데이터)  (0) 2020.02.17
손글씨 분류 실습  (0) 2020.02.17
보스턴주택 값 예측  (0) 2020.02.17
Linear Model - Regression  (0) 2020.02.17