본문 바로가기
  • 문과생의 백엔드 개발자 성장기
|Playdata_study/AI

210805_MachinLearning 2 (Decision Tree)

by 케리's 2021. 8. 5.

실습

 

03_ML_SVM_point

 

선형으로 분리되는 데이터 실습하기

 

import sys, os
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn import svm
from sklearn.model_selection import train_test_split, GridSearchCV

 

 

Custom Funtion Definition

 

red_RGB = (1, 0, 0)
blue_RGB = (0, 0, 1)
data_colors = [red_RGB, blue_RGB]

def read_points_file(filename):
    points = []
    with open(filename, "r") as f:
        for point in f:
            point = point.strip("\n").split()
            points.append([float(point[0]), float(point[1])])
    return points

def read_data(class_0_file, class_1_file):
    points_label0 = read_points_file(class_0_file)
    points_label1 = read_points_file(class_1_file)
    points = points_label0 + points_label1
    points = np.array(points)
    
    label0, label1 = [0], [1]
    num_of_label0, num_of_label1 = len(points_label0), len(points_label1)
    labels = label0 * num_of_label0 + label1 * num_of_label1
    
    return (points, labels)



def get_colors(y):
    return [data_colors[label] for label in y]

def plot_data(X_train, y_train, X_test, y_test):
  
    X = np.concatenate((X_train, X_test)) #concatenate 배열을 하나로 합침
    y = np.concatenate((y_train, y_test))

    colors = get_colors(y)
    colors_train = get_colors(y_train)
    colors_test = get_colors(y_test)

    plt.figure(figsize=(8, 4))

    # Plot all data plot
    plt.subplot(131)
    plt.axis('equal')
    plt.scatter(X[:, 0], X[:, 1], c=colors, s=10, edgecolors=colors)
    plt.title("Data (100%)")


    # training data plot
    plt.subplot(132)
    plt.axis('equal')
    #plt.axis('off')
    plt.scatter(X_train[:, 0], X_train[:, 1], c = colors_train, s = 10, edgecolors=colors_train)
    plt.title("Training Data (80%)")

    # testing data plot
    plt.subplot(133)
    plt.axis('equal')
    #plt.axis('off')
    plt.scatter(X_test[:, 0], X_test[:, 1], c = colors_test, s = 10, edgecolors=colors_test)
    plt.title("Test Data (20%)")
    plt.tight_layout()
    plt.show()

def plot_decision_function(X_train, y_train, X_test, y_test, clf):
    plt.figure(figsize=(8, 4))
    plt.subplot(121)
    plt.title("Training data")
    plot_decision_function_helper(X_train, y_train, clf)
    plt.subplot(122)
    plt.title("Test data")
    plot_decision_function_helper(X_test, y_test, clf, True)
    plt.show()

def plot_decision_function_helper(X, y, clf, show_only_decision_function = False):

    colors = get_colors(y)
    plt.axis('equal')
    plt.tight_layout()
    #plt.axis('off')

    plt.scatter(X[:, 0], X[:, 1], c=colors, s=10, edgecolors=colors)
    ax = plt.gca()  ## get current axes
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()

    # Create grid to evaluate model
    xx = np.linspace(xlim[0], xlim[1], 30)
    yy = np.linspace(ylim[0], ylim[1], 30)
    YY, XX = np.meshgrid(yy, xx)
    xy = np.vstack([XX.ravel(), YY.ravel()]).T # xy.shape = (900, 2)   ## ravel()은 flatten() 함수
    Z = clf.decision_function(xy).reshape(XX.shape)
    # clf.decision_function(xy).shape = (900,)
    # Z.shape = (30, 30)

    if  show_only_decision_function:
    # Plot decision boundary
        ax.contour(XX, YY, Z, colors='k', levels=[0], alpha=0.5,
                 linestyles=['-'])
    else :
    # Plot decision boundary and margins
        ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5,
                 linestyles=['--', '-', '--'])

 

DataLoader

 

# 노이즈가 전혀 없어서 아주 깔끔하게 선형 구분이 가능한 데이터를 다루겠다.

X, labels = (read_data("../data/points_class_0.txt","../data/points_class_1.txt"))

 

Data Split

 

#Split data to train and test on 80-20 ratio

# train feature, test feature, train labels, test labels 
X_train, X_test, y_train, y_test = train_test_split(X, labels, test_size=0.2, random_state=0)

# train_test_split 를 사용했기 떄문에 자동적으로 아래와 같이 표현됨
# Plot Data
plot_data(X_train, y_train, X_test, y_test)

 

Model Generator and Training (모델생성, 트레이닝)

 

# 곧은 선형으로 단순 분류를 하고자 한다면 kernel = "linear"를 지정한다

clf = svm.SVC(kernel = "linear")
clf.fit(X_train, y_train) # fit은 training data 함수이다, test data는 predict()
# ---- 결과 

SVC(kernel='linear')

 

 

Predict and Accuracy Score (예측)

 

clf_pred = clf.predict(X_test) # 예측

#Plot Data
plot_decision_function(X_train, y_train, X_test, y_test, clf)

# score() 함수 :: X_test를 가지고 내부적으로 Pred 돌린 후 y_test와 비교해서 검사
print("Accuracy : {}%".format(clf.score(X_test, y_test)*100))

 

 

 

 

선형으로 분리되지 않는 데이터 실습하기

 

이전 데이터와는 조금 다르게 노이즈값이 조금 끼어져 있는 학습데이터를 다룬다.
이럴때는 cost 파라미터를 사용해서 Decision Boundary를 조정할 수 있다.
또한 선형으로 분리되지 않는 데이터는 다른 파라미터 값으로 조정해야 한다.

 

 

Data Loader

 

X, labels = (read_data("../data/points_class_0_nonLinear.txt","../data/points_class_1_nonLinear.txt"))

 

 

Data Split

 

# Split data to train and test on 80-20 ratio
X_train, X_test,y_train, y_test = train_test_split(X,labels,test_size=0.2,random_state=0)

#Plot Data
plot_data(X_train,y_train,X_test,y_test)

 

 

 

Model Generator (머신에 입력)

 

# radial basis function(가우시안 방사 기저함수)
# rdf-- radial basis function 사용시 cost와 gamma값도 줘야한다!

clf = svm.SVC(kernel="rbf", C=10.0, gamma = 0.1)


# cost, gamma를 정해주는 기준이 뭘까? 다 넣어봐야 알 수 있다.
# 추천값 + 경험 

# 하이퍼 파라미터란? Model이 학습을 통해서 찾아낼 수 없는 값, cost, gamma 값을 의미한다.
# 교차검증이 필요: gridSearch ::  잘안쓴다? 왜때문이지?

clf.fit(X_train, y_train) # training

 

 

Training and Predict

 

clf_pred = clf.predict(X_test) # predict

plot_decision_function(X_train,y_train,X_test,y_test,clf)

 

 

GridSearch

 

cost, gamma에 해당하는 여러개의 값들을 그리드한 모양으로 서치해보겠다는 기법

최적의 파라미터 값을 찾도록 내부적으로 교차검증이 이뤄진다

 

param_id = {'C':[0.1,1,10,100],'gamma':[1,0.1,0.01,0.001,10]}
clf_grid = GridSearchCV(svm.SVC(), param_grid=param_id) # 모델생성을 gridserch 에 한다

# 학습
clf_grid.fit(X_train,y_train)

# grid search 그래프
plot_decision_function(X_train,y_train,X_test,y_test,clf_grid)

# best hyperparameter 값을 찾아준다
print("Best Parameters: \n", clf_grid.best_params_)
print("Best Estmaters: \n", clf_grid.best_estimator_)

 

 

 

Model Generator 2 

cost, gamma 값을 찾고 다시 적용해보기

 

clf = svm.SVC(kernel="rbf", C=1,gamma = 0.01)
clf.fit(X_train, y_train)
clf_pred = clf.predict(X_test)
plot_decision_function(X_train,y_train,X_test,y_test,clf)

 

 

04_ML_SVM_titanic

 

 

 컬럼 설명

(데이터는 다음의 링크에서 다운받으실 수 있습니다)

  • Survival - 생존 여부. 0이면 사망, 1이면 생존한 것으로 간주합니다.
  • Pclass - 티켓 등급. 1등석(1), 2등석(2), 3등석(3)이 있으며, 1등석일수록 좋고 3등석일수록 좋지 않습니다.
  • Sex - 성별. 남자(male)와 여자(female)로 구분됩니다.
  • Age - 나이입니다. 틈틈히 빈 값이 존재하며, 소수점 값도 존재합니다.
  • SibSp - 해당 승객과 같이 탑승한 형재/자매(siblings)와 배우자(spouses)의 총 인원 수입니다.
  • Parch - 해당 승객과 같이 탑승한 부모(parents)와 자식(children)의 총 인원 수입니다.
  • Ticket - 티켓 번호입니다. 다양한 텍스트(문자열)로 구성되어 있습니다.
  • Fare - 운임 요금입니다. 소수점으로 구성되어 있습니다.
  • Cabin - 객실 번호입니다. 많은 빈 값이 존재하며, 다양한 텍스트(문자열)로 구성되어 있습니다.
  • Embarked - 선착장입니다. C는 셰르부르(Cherbourg)라는 프랑스 지역, Q는 퀸스타운(Queenstown)이라는 영국 * * 지역, S는 사우스햄튼(Southampton)이라는 영국 지역입니다.

 

 

작업 순서

I. Load Dataset

II. Explore

III. Pre Processing 

---- 데이터 분석 

IV. Model Generator

V. Accuracy Measure

VI. Inference Test Predict

---- 머신러닝 

VII. Submit

 

 

I. Load Dataset

 

import pandas as pd

train = pd.read_csv('../data/train.csv')
test = pd.read_csv('../data/test.csv')

train.head(1) # survived :: label = 정답
test.head(1) 

# test에는 label이 왜없을까 ? inference 데이터 셋이기 때문에
# 1. Validation Test
# 2. Inference Test:: label이 없음, 상용화 전 test

 

train.head(1)

 

test.head(1)

 

 

train.shape   
test.shape
# --- 결과
# colums 갯수 없는 것 확인

(891, 8)
(418, 11)

 

 

train.info()  # 누락데이터를 보지만, 0값으로 채워진것 또한 체크해야함
# --- 결과

<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

 

test.info()
# --- 결과
# Sex, Age, Cabin, Embarked = 누락데이터, 생존여부에 영향을 미치면 처리를 잘해야하고 관련없으면 drop

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 11 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  418 non-null    int64  
 1   Pclass       418 non-null    int64  
 2   Name         418 non-null    object 
 3   Sex          418 non-null    object 
 4   Age          332 non-null    float64
 5   SibSp        418 non-null    int64  
 6   Parch        418 non-null    int64  
 7   Ticket       418 non-null    object 
 8   Fare         417 non-null    float64
 9   Cabin        91 non-null     object 
 10  Embarked     418 non-null    object 
dtypes: float64(2), int64(4), object(5)
memory usage: 36.0+ KB

 

 

II. Explore

 

과학적이고 정확도 높은 분석을 하기 위해서는 학습에 적합한 Feature를 찾아내고

정제하는 과정이 먼저 선행되어져 있어야만 가능하다. 이 과정을 Feature Engineering이라고 한다.

 

# -- 선실종류에 따른 생존확률 

survived = train.loc[train['Survived']==1, 'Pclass'].value_counts()
survived

dead = train.loc[train['Survived']==0, 'Pclass'].value_counts()
dead

df = pd.DataFrame([survived, dead], index=['Survived','Dead'])
df

 

 

# -- 기본이 되는 알고리즘으로 돌아가기 위해 함수를 만들자
# -- 변수처리 (여러 값이 들어가서 비교 하기위해)

import matplotlib.pyplot as plt
import seaborn as sns

def bar_chart(feature):
    survived = train.loc[train['Survived']==1, feature].value_counts()
    dead = train.loc[train['Survived']==0, feature].value_counts()
    
    df = pd.DataFrame([survived, dead], index = ['Survived', 'Dead'])
    df. plot(kind = 'bar', figsize = (15, 10)) # 시각화
    plt.show()

 

Feature - Pclass

 

다음으로 분석할 컬럼은 객실 등급(Pclass) 이다.

객실 등급은 크게 1등급(=퍼스트 클래스), 2등급(=비즈니스), 3등급(=이코노미) 로 나뉜다.

추측컨데 객실 등급이 높을 수록 더 많은 비용을 지불한 타이타닉호의 VIP라고 볼 수 있다.

성별(Sex) 컬럼과 마찬가지로, 객실 등급(Pclass) 컬럼도 countplot으로 간단하게 분석할 수 있다.

 

sns.countplot(data=train, x="Pclass", hue="Survived")

bar_chart('Pclass')
#bar_chart('feature')

 

분석 결과 객실 등급(Pclass)이 높을수록 생존 확률이 더 높다는 것을 알 수 있다.

조금 더 구체적으로 살펴보자면

  • 1등급은 생존자의 인원 수가 사망자의 인원 수보다 더 많지만, 2등급과 3등급은 그렇지 않다.
  • 3등급의 경우 생존자의 인원 수보다 사망자의 인원 수가 압도적으로 높다.

 

 

이번에는 pivot table로 객실 등급(Pclass) 컬럼을 분석해보겠습니다.

 

 

# --- 수치로 보기

pd.pivot_table(train, index="Pclass", values="Survived")

 

 

분석 결과 객실 등급(Pclass)이 높을수록 생존률이 높다는 사실을 알 수 있었고,

특히나 객실 등급(Pclass)이 2등급인 경우 생존률이 1/2(50%),

3등급인 경우 생존률이 1/4(25%)도 되지 않는다는 사실을 발견할 수 있었다.

 

>>> Pclass 속성은 모두 지도학습에 사용하게 될 속성으로 추출한다

 

 

 

Feature - Fare

 

 

요금이 저렴할수록 사망율이 높다.
Pclass가 사망, 생존에 영향을 미치는 특징임을 확인했다면

다음으로 해당 특징과 연결되어 있는 특징을 다시 찾아보는 과정은 필수적이다.

  • 이 분석은 바로 위에서 결과로 확인했던 Pclass와 연관성이 매우 깊다.
  • 3등석 요금이 저렴하기 때문이다.
  • Feature요소를 추출하는데 있어서 Fare , Pclass 는 생존율과 사망율에 모두 연결되어진다.

>>> Fare 속성은 모두 지도학습에 사용하게 될 속성으로 추출한다.

 

 

# facetgrid() :: 여러 내용을 한번에 비교할 때 사용

facet = sns.FacetGrid(train, hue="Survived",aspect=4)
facet.map(sns.kdeplot,'Fare',shade= True)
facet.set(xlim=(0, train['Fare'].max()))
facet.add_legend()
plt.xlim(0,180)
plt.show()

 

 

 

Feature - Sex

 

  • 여성일수록 생존률이 높다
  • 성별(Sex) 컬럼은 타이타닉 데이터셋에서 가장 중요한 컬럼 중 하나입니다.

 

bar_chart('Sex')

분석 결과 여성 승객(female)이 남성 승객(male)에 비해 압도적으로 생존 확률이 높다는 것을 파악할 수 있다.

이는 남성 승객이 여성 승객보다 압도적으로 생존 확률이 낮다는 것을 뜻한다.

비슷한 결과를 엑셀이나 pandas의 pivot table로 도출해 낼 수 있다.

 

 

pd.pivot_table(train, index="Sex", values="Survived")

>>> Sex 속성도 지도학습을 위한 Feature로 추출한다.

 

 

 

1) 데이터의 전반적인 분포를 알고 싶다면 데이터 시각화를,
2) 통계치 하나하나의 구체적인 수치를 보고 싶다면 pivot_table을 사용하는 것이 좋다.

 

 

 

Feature - Age

 

  • 나이가 어릴수록 생존률이 높았다.
  • 20~30대에서는 오히려 사망률이 더 높게 측정되었다.

 

# 구간이 중요해서 facetgrid()

facet = sns.FacetGrid(train, hue="Survived",aspect=4)
facet.map(sns.kdeplot,'Age',shade= True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
 
plt.show()

 

>>> Age 속성도 지도학습을 위한 Feature로 추출한다.

 

 

 

Feature - Title (가공이필요)

 

  • 외국사람의 이름에는 항상 Mr, Miss, Mrs 단어가 붙는다
  • 이름만 보고도 그사람의 대강의 나이와 성별 판단이 가능하다.
  • 이전 분석결과를 바탕으로 보면, Miss일수록 생존확률이 높을 것이고. 반면에 Mr는 사망확률이 높을 것이다

 

train_test_data= [train, test] 
'''
정규식 표현법 사용
공백으로 시작하고
.으로 끝나는 데이타를 추출

Mr : 0 
Miss : 1
Mrs : 2
etc : 3

'''
for dataset in train_test_data:
    dataset['Title'] = dataset['Name'].str.extract(' ([A-Za-z]+)\.', expand=False)

title_mapping = {"Mr": "Mr", "Miss": "Miss", "Mrs": "Mrs", 
                 "Master": "etc", "Dr": "etc", "Rev": "etc", "Col": "etc", "Major": "etc", "Mlle": "etc","Countess": "etc",
                 "Ms": "etc", "Lady": "etc", "Jonkheer": "etc", "Don": "etc", "Dona" : "etc", "Mme": "etc","Capt": "etc","Sir": "etc" }
for dataset in train_test_data:
    dataset['Title'] = dataset['Title'].map(title_mapping)
    
train.drop('Name', axis=1, inplace=True)
test.drop('Name', axis=1, inplace=True)
bar_chart('Title')

 

>>> Title 속성도 지도학습을 위한 Feature로 추출한다.

 

 

 

Feature - Family Size

 

  • 같이 동반한 가족의 수가 없다면 사망할 확률이 높다.
  • 가족이 1명이나 2명일 경우에는 생존자가 미세하지만 조금 더 많이 나온다
  • 가족이 3명일때 생존자가 더 많다.

 

train["FamilySize"] = train["SibSp"] + train["Parch"]
test["FamilySize"] = test["SibSp"] + test["Parch"]
train.drop('SibSp', axis=1, inplace=True)
test.drop('SibSp', axis=1, inplace=True)
train.drop('Parch', axis=1, inplace=True)
test.drop('Parch', axis=1, inplace=True)

bar_chart('FamilySize')

 

 

>>> 같이 동반한 가족의 수도 생존 사망과 연관이 있다. 지도학습에 대상으로 동반가족수 Feature도 추출한다.

 

 

 

 Feature - Embarked

 

  • S선착장에서 탑승한 사람일수록 사망률 높다.
  • C선착장에서 탐승한 사람일수록 생존률 높다.

 

bar_chart('Embarked')

 

>>> Embarked 속성도 지도학습을 위한 Feature로 추출한다.

 

 

 

III. Pre Processing

 

모델을 생성해서 머신러닝(Machine Learning) 알고리즘에 넣기 위해서는(Training 과정),

데이터를 머신러닝 알고리즘이 이해할 수 있는 형태로 변환해줘야 한다.

이 과정을 전문용어로 전처리(Preprocessing)라고 한다.

 

 

scikit-learn 에서 제공하는 머신러닝 알고리즘에 데이터를 넣을 수 있는 기본 조건은 다음과 같다.

 

  1. 불필요한 속성은 과감히 제거한다
  2. Fill in Missing Value(데이터에 빈 값이 없어야 한다) - 결측치 값에 대한 전략이 필요함
  3. 모든 데이터는 숫자(정수형, 소수점 등)로 구성되어 있어야 한다. → Encoding, Binning 2가지 방법

 

타이타닉 데이터에 있는 세 컬럼(Sex, Fare, Embarked)을 전처리해 본다.

 

 

 

1. 관련없는 데이터 속성을 삭제

  • Ticket
  • Cabin
  • PassengerId

 

train.drop('Ticket', axis=1, inplace=True)
test.drop('Ticket', axis=1, inplace=True)

train.drop('Cabin', axis=1, inplace=True)
test.drop('Cabin', axis=1, inplace=True)

test_PassengerId=test["PassengerId"]
train.drop('PassengerId', axis = 1, inplace=True)
test.drop('PassengerId', axis = 1, inplace=True)

 

 

2. Fill in Missing Value

 

 

scikit-learn의 머신러닝 알고리즘에 데이터를 넣을 땐 언제나 데이터에 값이 채워져 있어야 한다.
만일 데이터에 NaN이라는 값이 있다면 이는 비어있다는 의미이며,
이 데이터를 머신러닝 알고리즘에 넣으면 에러가 발생한다.

 

  • Age

그룹별로 평균내서 결측값을 채운다.
Mr, Miss, Mrs 그룹 사람들의 나이 평균으로 채운다.

 

  • Fare

그룹별로 평균내서, 결측치 채우기
1등석은 1등석끼리,2등석은 2등석끼리,3등석은 3등석끼리 평균내서 채운다

 

  • Embarked

1등석, 2등석, 3등석 모든 등석에서 표를 구매한 선착장이 S가 가장 많았다.
1,2,3 등석 모두가 S선착장에서 구입한 비율이 50%를 넘어섰기 때문에 결측치값은 기본값을 S로 지정했다.

 

 

train["Age"].fillna(train.groupby("Title")["Age"].transform("median"), inplace=True)
test["Age"].fillna(test.groupby("Title")["Age"].transform("median"), inplace=True)
train["Fare"].fillna(train.groupby("Pclass")["Fare"].transform("median"), inplace=True)
test["Fare"].fillna(test.groupby("Pclass")["Fare"].transform("median"), inplace=True)
Pclass1 = train[train['Pclass']==1]['Embarked'].value_counts()
Pclass2 = train[train['Pclass']==2]['Embarked'].value_counts()
Pclass3 = train[train['Pclass']==3]['Embarked'].value_counts()

df = pd.DataFrame([Pclass1, Pclass2, Pclass3])
df.index = ['1st class','2nd class', '3rd class']
df.plot(kind='bar',stacked=True, figsize=(10,5))

for dataset in train_test_data:
    dataset['Embarked'] = dataset['Embarked'].fillna('S')

 

 

3. 모든 데이터는 숫자(정수형, 소수점 등)로 구성되어 있어야 한다.

 

3-1. Binning(구간화)

 

Binning은 대표적인 Feature Engineering 기법 중의 하나로 숫자형 변수를 범주형 변수로 변형하는 작업이다.

승객들을 해당 승객의 나이(숫자)에 따라 총 5구간으로 구분하는 작업(Binning)을 했다.

 

구간화(Binning)를 이용하면,
(1) 이상치로 발생 가능한 문제를 완화 시켜줄 수 있고,
(2) 결측치 처리를 보다 간편하게 할 수 있다.
(3) 과적합을 완화 시켜주는 효과가 있고,
(4) 결과에 대한 해석이 용이하다는 장점도 있다.
(5) Target 변수와의 관계가 비선형인 경우도 설명이 가능하다.

 

 

3-2. Encoding

 

성별 컬럼을 전처리하는 가장 쉬운 방법은 male은 0으로, female은 1로 바꿔주는 것이다.

이를 전문 용어로 인코딩(Encoding)이라고 한다.

여기서는 Sex, Embarked, Title 컬럼을 숫자로 매핑시켜 준다.

 

 

 

4  - Age Binning(구간화)

 

facet = sns.FacetGrid(train, hue="Survived",aspect=4)
facet.map(sns.kdeplot,'Age',shade= True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
 
plt.show()

 

for dataset in train_test_data:
    dataset.loc[ dataset['Age'] <= 10, 'Age'] = 0
    dataset.loc[(dataset['Age'] > 10) & (dataset['Age'] <= 22), 'Age'] = 1
    dataset.loc[(dataset['Age'] > 22) & (dataset['Age'] <= 34), 'Age'] = 2
    dataset.loc[(dataset['Age'] > 34) & (dataset['Age'] <= 62), 'Age'] = 3
    dataset.loc[ dataset['Age'] > 62, 'Age'] = 4

 

 

5  - Fare Binning(구간화)

 

facet = sns.FacetGrid(train, hue="Survived",aspect=4) # 구간을 4개로나눔
facet.map(sns.kdeplot,'Fare',shade= True)
facet.set(xlim=(0, train['Fare'].max()))
facet.add_legend()
plt.xlim(0,180)
plt.show()

 

for dataset in train_test_data:
    dataset.loc[ dataset['Fare'] <= 17, 'Fare'] = 0
    dataset.loc[(dataset['Fare'] > 17) & (dataset['Fare'] <= 30), 'Fare'] = 1
    dataset.loc[(dataset['Fare'] > 30) & (dataset['Fare'] <= 100), 'Fare'] = 2
    dataset.loc[ dataset['Fare'] > 100, 'Fare'] = 3

 

 

6  - Sex Encoding

 

sex_mapping = {"male": 0, "female": 1}
for dataset in train_test_data:
    dataset['Sex'] = dataset['Sex'].map(sex_mapping)

 

7  - Embarked Encoding

 

# 선착장을 숫자로 맵핑
embarked_mapping = {"S": 0, "C": 1, "Q": 2}
for dataset in train_test_data:
    dataset['Embarked'] = dataset['Embarked'].map(embarked_mapping)

 

8  - Title Encoding

 

title_mapping = {"Mr": 0, "Miss": 1, "Mrs": 2, "etc": 3}
for dataset in train_test_data:
    dataset['Title'] = dataset['Title'].map(title_mapping)

 

train.head()

test.head()

 

train_data = train.drop('Survived', axis=1)
train_data

 

train_label = train['Survived']
train_label
# ---- 결과

0      0
1      1
2      1
3      1
4      0
      ..
886    0
887    1
888    0
889    1
890    0
Name: Survived, Length: 891, dtype: int64

 

 

 

IV. Model Generator

 

이제 전처리(preprocessing)한 데이터를 활용해 Model을 생성해 본다.

지도학습(Supervised Learning) 이라고 불리우는 알고리즘은 여러가지가 있다.


우리는 지금까지 SVM으로만 모델을 학습시켜 왔는데 다른 모델을 생성해서 사용해 보기로 하자.
지도학습에는 어떤 모델들이 있는지 먼저 소개한다.

scikit-learn 분류방법 모델 사이트로 들어가서 어떤 것들이 있는지 확인해 보도록 하자.

 

여기 보면 각각의 알고리즘들이 어떻게 데이타를 분리하는지 나와있다.

Decision Tree , Random Forest, Ada Boost 등이 있다. 이것들은 우리가 앞으로 다룰 중요한 분류모델들 이다.

 

Supervised Learning 알고리즘을 학습시키기 위해서는 두 가지 타입의 데이터가 필요하다.

 

1) Label

  : 레이블(Label), 내지는 타겟 변수(Target Variable)이라고 부름. (Class라고도 정의)

   우리가 맞춰야 하는 정답,

   타이타닉 경진대회에서는 생존 여부(Survived)가 label이다.

 

2) Feature

  : 우리가 label을 맞추는데 도움이 되는 값들.

    타이타닉 데이터에서는 label을 제외한 대부분의 값들이 Feature가 될 수 있다.

 

 

※ 나는 이번 코드에서 다음의 컬럼을 Feature와 Label로 활용할 것이다.

 

Feature : 1) 티켓 등급(Pclass), 2) 성별(Sex_encode), 3) 운임요금(Fare_fillin), 그리고 4) 선착장(Embarked)

Label : 생존 여부(Survived)

 

이를 통해 train 데이터와 test 데이터를 다음의 세 가지 형태의 값으로 나눠보자.

 

 

1) X_train : train 데이터의 feature . 줄여서 X_train이라고 부름

2) X_test : test 데이터의 feature. 줄여서 X_test라고 부름

3) y_train : train 데이터의 label. 줄여서 y_train이라고 부름

 

y_test 라는 데이터는 존재하지 않는다.

test 데이터에는 생존 여부(Survived)를 나타내는 컬럼이 없기 때문이며,

목표 자체가 y_test에 해당하는 test 데이터의 생존 여부(Survived)를 예측하는 것이기 때문

X_train, y_train, X_test를 활용하여 y_test에 해당하는 값을 예측하는 것이 바로 Decision Tree의 역할

 

feature와 label을 정의한 뒤, 이를 활용해 X_train, X_test, y_train을 각각 만들어 본다.

 

 

from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn import svm
import numpy as np

from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score

# Validation test :: 학습데이터중 일부분을 쪼개서 검증 데이터로 사용
# k_fold 사용해서 validation 검증 하겠다!
# k_fold :: 전체를 n개로 나눈 후 모든 경우의 수를 test를 한 후 그것의 평균값을 accuracy로 측정
#           데이터셋이 턱없이 부족할 때 사용

k_fold = KFold(n_splits=10, shuffle=True, random_state=0)
# SVM
clf=svm.SVC(gamma = 'auto')
clf.fit(train_data, train_label) # 학습

prediction = clf.predict(test) # 예측, test_label은 없음
# 위 결과를 캐글에 제출하면 된다.

 

V. Accuracy

 

clf=svm.SVC(gamma = 'auto')
score_SVC = cross_val_score(clf, train_data, train_label, cv=k_fold, n_jobs=1, scoring='accuracy')

# cross_val_score () :: 교차검증을 위한 함수, cs로 폴드의 수 조정 가능
# cv는 몇개를 쪼갤건지, 여기서는 k_fold 값을 줌 (10개)
# n_jobs :: 현재 cpu중에서 몇 개를 뽑아 쓸건지, 거의 1로 사용 (전부 다 돌리겠다)
# scoring :: accuracy , validation 의 성능 측정 할수있음



# 정확도 확인
print("SVM :: ", round(np.mean(score_SVC)*100,2))
# ---- 결과

SVM ::  83.05

 

 

VI. Inference Test Predict

 

clf=svm.SVC(gamma = 'auto')
clf.fit(train_data, train_label)

prediction = clf.predict(test) # 0,1,0,0 값이 들어있음

 

 

VII.Kaggle Submit

# 예측한 결과를 CSV로 만들어서 Kaggle 측에다 제출해 보겠다.

submission = pd.DataFrame({
    "PassengerId" : test_PassengerId, # 어떤 사람이 죽고 살았는지 구분하기 위해 사용
    "Survived":prediction # 0,1,0,0 값이 들어있음
})
submission.to_csv("submission.csv", index=False)
submission = pd.read_csv("submission.csv")
submission.head()


 

Hyper Parameter Tuning

 

하이퍼 매개 변수 튜닝 은 최상의 성능을 발휘하는 하이퍼 매개 변수 구성을 찾는 프로세스.

프로세스는 일반적으로 계산 비용이 많이 들고 수동입니다.

ex, GridSearch 방법을 통해 최적화된 교차검증방법 찾음

 

 

 

Closs Validation (CV, 교차검증)

교차 검증은 train set을 train set + validation set으로 분리한 뒤, validation set을 사용해 검증하는 방식이다.

 

 

 


 

Decision Tree

 

 

결정트리(의사결정나무, 의사결정트리)는 특정기준(질문=Feature)에 따라 데이터를 구분하는 모델

분류와 회귀 문제에서 널리 사용되는 모델 

 

ex) 날개가 있나요? 날수 있나요? 지느러미가 있나요? 등 사용해서 4개의 클래스를 구분하는 모델 

 

 

구조

결정 트리에서 질문이나 네모상자를 Node라고 한다.

맨 위의 노드(첫 질문)를 Root Node ,

마지막 노드 Leaf Node 라 한다.

엣지(edge)는 질문의 답과 질문을 연결 하는 선을 말한다.

 

전체적인 모양이 나무를 뒤집어 놓은 것과 닮았다고 해서 붙여진 이름이 Decision Tree이다.

 

 

 

목적과 특징

 

불순도를 얼마나 낮게 낮추는 것이 목적

깊이, depth (의사결정)를 높이는 것은 불순도 0%로 하기 위함이다

순수 Node로만 (순도 100%) 이뤄진 것 = Full Tree 

 → Overfitting 발생 가능성이 높다 → Pruning(가지치기) 

 

 

즉, 

데이터를 분할하는 핵심 원리는 (의사결정하는 기본적인 메카니즘은) 

 

분할된 영역이 한가지 종류의 타켓을 가질 때 까지 반복 된다. = depth 가 깊어진다.

순수노드로만 이루어진 트리가 최종적으로 만들어 진다. = Full Node라 한다.

 

FullNode는 훈련 데이터 셋에 대해서는 100% 정확도를 가지는 반면에,

Test 데이터 셋에는 오버피팅 되는 경향을 보인다. 

 

학습된 데이터의 정답 예측은 매우 좋은 반면에,

새로운 데이터 예측률은 많이 떨어지는 것이 보통이다. 

 

오버피팅을 낮추기 위해서는 Pruning 기법 사용한다.

 

 

 

가지치기 (Pruning)

최대 트리로 형성된 결정트리의 특정노드 밑의 하부 트리를 제거하여 일반화 성능을 높히는 것을 의미

트리에 가지가 너무 많으면 오버핏팅이라고 하고, 오버핏팅을 막기위한 방법으로 가지치기를 한다.

 

가지치기란 말 그대로 나무의 가지를 치는 작업을 말하는데

가지의 depth, leaf node의 최대 갯수, 노드가 분할하는 최대 개수같은 속성을 제한하는 방법이다. 

 

 

1. max_depth = 4, 5 정도 준다

   : tree 의 깊이 제한 

2. min_sample_split 

 : 파라미터를 조정하여 한 노드에 들어있는 최소 데이터 수를 정해준다.

 

 

 

알고리즘 : 엔트로피 (Entropy), 불순도 (Impurity)

불순도(Impurity)란 해당 범주 안에 서로 다른 데이터가 얼마나 섞여 있는 지를 뜻함

 

엔트로피 (Entropy)는 불순도를 수치적으로 나타낸 척도 

  : 엔트로피가 1이면 불순도가 최대 

결정트리는 불순도를 최소화(혹은 순도를 최대화) 하는 방향으로 학습을 진행

 

 

 


05_ML_DecisionTree_iris

 

 

1. Data Loader - sklearn datasets.load_iris()

 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
iris = datasets.load_iris()
iris 

# sklearn의 data는  feature(data), label(target)으로 분리되어 있음
# ---- 결과
# 'target_names': array(['setosa', 'versicolor', 'virginica'], dtype='<U10'),
# 'feature_names': ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'],

# 'filename': 'C:\\anaconda3\\lib\\site-packages\\sklearn\\datasets\\data\\iris.csv'}
 
 
{'data': array([[5.1, 3.5, 1.4, 0.2],
        [4.9, 3. , 1.4, 0.2],
        [4.7, 3.2, 1.3, 0.2],
        [4.6, 3.1, 1.5, 0.2],
        [5. , 3.6, 1.4, 0.2],
        [5.4, 3.9, 1.7, 0.4],
        [4.6, 3.4, 1.4, 0.3],
        [5. , 3.4, 1.5, 0.2],
        [4.4, 2.9, 1.4, 0.2],
        [4.9, 3.1, 1.5, 0.1],
        [5.4, 3.7, 1.5, 0.2],
        [4.8, 3.4, 1.6, 0.2],
        [4.8, 3. , 1.4, 0.1],
        [4.3, 3. , 1.1, 0.1],
        [5.8, 4. , 1.2, 0.2],
        [5.7, 4.4, 1.5, 0.4],
        [5.4, 3.9, 1.3, 0.4],
        [5.1, 3.5, 1.4, 0.3],
        [5.7, 3.8, 1.7, 0.3],
        [5.1, 3.8, 1.5, 0.3],
        [5.4, 3.4, 1.7, 0.2],
        [5.1, 3.7, 1.5, 0.4],
        [4.6, 3.6, 1. , 0.2],
        [5.1, 3.3, 1.7, 0.5],
        [4.8, 3.4, 1.9, 0.2],
        [5. , 3. , 1.6, 0.2],
        [5. , 3.4, 1.6, 0.4],
        [5.2, 3.5, 1.5, 0.2],
        [5.2, 3.4, 1.4, 0.2],
        [4.7, 3.2, 1.6, 0.2],
        [4.8, 3.1, 1.6, 0.2],
        [5.4, 3.4, 1.5, 0.4],
        [5.2, 4.1, 1.5, 0.1],
        [5.5, 4.2, 1.4, 0.2],
        [4.9, 3.1, 1.5, 0.2],
        [5. , 3.2, 1.2, 0.2],
        [5.5, 3.5, 1.3, 0.2],
        [4.9, 3.6, 1.4, 0.1],
        [4.4, 3. , 1.3, 0.2],
        [5.1, 3.4, 1.5, 0.2],
        [5. , 3.5, 1.3, 0.3],
....}

 

 

iris.feature_names
# --- 결과 

['sepal length (cm)',
 'sepal width (cm)',
 'petal length (cm)',
 'petal width (cm)']
iris.target_names
# ---- 결과

array(['setosa', 'versicolor', 'virginica'], dtype='<U10')

 

 

print(iris.data.shape)
print(iris.target.shape)
iris.data
# ---- 결과

(150, 4)
(150,)
array([[5.1, 3.5, 1.4, 0.2],
       [4.9, 3. , 1.4, 0.2],
       [4.7, 3.2, 1.3, 0.2],
       [4.6, 3.1, 1.5, 0.2],
       [5. , 3.6, 1.4, 0.2],
       [5.4, 3.9, 1.7, 0.4],
       [4.6, 3.4, 1.4, 0.3],
       [5. , 3.4, 1.5, 0.2],
       [4.4, 2.9, 1.4, 0.2],
       [4.9, 3.1, 1.5, 0.1],
       [5.4, 3.7, 1.5, 0.2],
       [4.8, 3.4, 1.6, 0.2],
       [4.8, 3. , 1.4, 0.1],
       [4.3, 3. , 1.1, 0.1],
       [5.8, 4. , 1.2, 0.2],
       [5.7, 4.4, 1.5, 0.4],
...])

 

 

1.1 DataFrame Visualization

 

df = pd.DataFrame(iris.data, columns=iris.feature_names)
df

 

 

#### species 추가
df['species'] = np.array([iris.target_names[i] for i in iris.target])
df

 

 

 

1.2  Seaborn Visualization

 

sns.pairplot(df, hue = 'species')

 

 

 

2  머신러닝 연결하기

 

iris Data Shuffle/Split

 

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=0)

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

 

# ---- 결과 

(120, 4)
(30, 4)
(120,)
(30,)

 

 

 

2.1  모델 생성하기

 

from sklearn.tree import DecisionTreeClassifier
iris_tree = DecisionTreeClassifier(random_state=100)
iris_tree.fit(X_train, y_train) # 학습
# ---- 결과

DecisionTreeClassifier(random_state=100)

 

 

3  예측하기

 

pred = iris_tree.predict(X_test)

print("예측결과", pred)
print("정답", y_test)
# ---- 결과

예측결과 [2 1 0 2 0 2 0 1 1 1 2 1 1 1 1 0 1 1 0 0 2 1 0 0 2 0 0 1 1 0]
정답 [2 1 0 2 0 2 0 1 1 1 2 1 1 1 1 0 1 1 0 0 2 1 0 0 2 0 0 1 1 0]

 

 

4  Accuracy Evaluation - accuracy_score(), score()

: 정확도 평가함수

 

# score () :: 내부적으로 predict 가 자동으로 수행

score_train = iris_tree.score(X_train, y_train)
score_test = iris_tree.score(X_test, y_test)

print("{:.3f}".format(score_train))
print("{:.3f}".format(score_test))
# ---- 결과 

1.000
1.000

 

# accuracy_score() :: 예측한 후 정답 값 비교할 때 사용

from sklearn.metrics import accuracy_score

accuracy_score(pred, y_test)
# ---- 결과

1.0

 

 

5  Pruning

 

# - (max_depth=3, 하이퍼 파라미터)

model = DecisionTreeClassifier(max_depth=3, random_state=0)
model.fit(X_train, y_train)

score_train = model.score(X_train, y_train)
score_test = model.score(X_test, y_test)

print("{:.3f}".format(score_train))
print("{:.3f}".format(score_test))
# --- 결과

0.967
0.967

 

 

6  Ggrapviz Visualization

 

import graphviz
from sklearn.tree import export_graphviz
export_graphviz(iris_tree, out_file="iris_tree.dot", 
                class_names = iris.target_names,
                feature_names = iris.feature_names,
                impurity = True, 
                filled = True 
               )

with open('iris_tree.dot', encoding='utf-8') as f:
    dot_graph = f.read()
    
dot = graphviz.Source(dot_graph)
display(dot)



dot.render(filename="iris_tree.png")

 

export_graphviz(model, out_file="model.dot", 
                class_names = iris.target_names,
                feature_names = iris.feature_names,
                impurity = True, # defalut값 false -> gini 미출력
                filled = True # node 색을 다 다르게 만들어 줌!
               )

with open('model.dot', encoding='utf-8') as f:
    dot_graph = f.read()
    
dot = graphviz.Source(dot_graph)
display(dot)

dot.render(filename="model.png") # 'model.png.pdf'도 같이 생성됨!

불순도를 낮추기 위해 의사결정이 필요하다

즉, 가장 상위에 있는 Node의 특징이 가장 중요한 특징이다. 

but, 같은 레벨에서는 중요도를 따지기 힘들다.

 

댓글