#!/usr/bin/env python3


1. PCA -- eigen face


PCA는 원본 데이터 표현보다 분석하기에 더 적합한 표현을 찾을 수 있으리란 생각에서 출발

이미지는 RGB의 강도가 기록된 픽셀로 구성

PCA를 이용하여 LFW(Labeled Faces in the Wild) 데이터셋의 이미지에서 특성을 추출


# library import

from sklearn.datasets import fetch_lfw_people # fetch_lfw_people library

import matplotlib.pyplot as plt

import matplotlib

import numpy as np


# matplotlib 설정

matplotlib.rc('font', family='AppleGothic'# 한글출력

plt.rcParams['axes.unicode_minus'] = False # 축 - 표시


people = fetch_lfw_people(min_faces_per_person=20, resize=0.7, color=False# 추출된 사진의 서로 다른 얼굴의 수, 사진 비율, 흑백여부

image_shape = people.images[0].shape # people객체 image의 첫번째 원소의 모양

print('people.images의 형태 \n{}'.format(people.images.shape)) # people객체의 image 형태: (3023, 87, 65)

print('class 갯수 \n{}'.format(len(people.target_names))) # people객체의 class 갯수, 62


fig, axes = plt.subplots(2, 5, # figure객체와 2x5의 plot객체를 각각 할당

                         subplot_kw={'xticks': (), 'yticks': ()}) # subplot의 축 설정; x축 눈굼없게, y축 눈금없게


# axes.ravel() : 리스트를 1차원으로

for target, image, ax in zip(people.target, people.images, axes.ravel()): # people.target, people.images, axes.ravel()에서 하나씩 원소 할당

    ax.imshow(image) # imshow로 그림 출력

    ax.set_title(people.target_names[target]) # 각 subplot의 타이틀

plt.gray() # 그림 흑백

plt.show() # 그래프 출력

LFW 데이터셋에 있는 이미지의 샘플



1 -1 people 객체 분석

# 각 target이 나타난 횟수 계산

counts = np.bincount(people.target) # people.target의 빈도 계산


# target별 이름과 횟수 출력

### enumerate() : 각 원소에 인덱스 부여

### print('{0:25}, {1:3}').format(var1, var2):  첫번째 {}에 var1과 25자리까지, 두번째{}에 var2와 3자리를 부여

### print({0!s}.format(var1)): print문에 전달된 형식이 숫자라도 문자로 처리

print('frequency')

for i, (count, name) in enumerate(zip(counts, people.target_names)):

    print('{0:25} {1:3}'.format(name, count), end= '\t'# name에서 25자리, count에서 3자리, 끝은 탭

    if (i + 1) % 3 == 0: # 3의 배수이면, 즉 4번째 원소부터

        print() # 개행처리


# Geoge W Bush와 Colin Powell의 이미지가 많음을 확인


### 데이터셋의 편중을 막기 위해 50개의 이미지만 선택

mask = np.zeros(people.target.shape, dtype=np.bool) # 3023개의 boolean타입 False 생성


people_unique = np.unique(people.target) # 중복된 값 제외

for target in people_unique: # 중복을 제거한 target리스트에서 한개의 원소 선택

# people.target(3023개의 리스트)중 선택된 원소와 같은 것만 출력 ==> [0] 리스트의 원소로 접근 ==> False의 갯수 50개까지 출력

# 이 논리 값을 mask의 인덱스로 사용 후 True로 변환

    mask[np.where(people.target == target)[0][:50]] = 1 

x_people = people.data[mask] # 훈련 데이터 생성

y_people = people.target[mask] # 테스트 데이터 생성


# 전처리 메소드 import

from sklearn.preprocessing import MinMaxScaler


scaler = MinMaxScaler()

x_people_scaled = scaler.fit_transform(x_people) # 전처리 메소드 적용


# 머신 러닝 library import

from sklearn.neighbors import KNeighborsClassifier

from sklearn.model_selection import train_test_split


# 전처리한 데이터를 분할

x_train, x_test, y_train, y_test = \

  train_test_split(x_people_scaled, y_people, # 분할할 데이터

                   stratify=y_people, random_state=0) # 그룹화할 데이터, 랜덤상태


# 머신 러닝 라이브러리 import

knn = KNeighborsClassifier(n_neighbors=1) # 이웃의 수

knn.fit(x_train, y_train) # 모델 학습


print('knn.score(x_test, y_test) \n최근접이웃의 일반화 세트 점수: {:.3f}'.format(

    knn.score(x_test, y_test))) # 0.248

정확도가 24.8%, 무작위로 분류하는 정확도는 1/62 = 1.6%


얼굴의 유사도를 측정하기 위해 원본 픽셀 공간에서 거리를 계산하는 것은 비효율적

각 픽셀의 회색톤 값을 다른 이미지에서 동일한 위치에 있는 픽셀 값과 비교. 이런 방식은 사람이 얼굴 이미지를 인식하는 것과는 많이 다르고, 픽셀을 있는 그대로 비교하는 방식으로는 얼굴의 특징을 잡아내기 어려움


2. PCA whitening 분석


픽셀을 비교할 때 얼굴 위치가 한 픽셀만 오른쪽으로 이동해도 큰 차이를 만들어 완전히 다른얼굴로 인식

주성분으로 변환하여 거리를 계산하여 정확도를 높이는 방법을 사용, PCA whitening 옵션을 사용하여 주성분의 스케일이 같아지도록 조정 ==> whitening 옵션 없이 변환 후 StandardScaler를 적용하는 것과 같음


# library import

import mglearn

mglearn.plots.plot_pca_whitening()

plt.show()

whitening옵션을 사용한 PCA 데이터 변환


데이터가 회전하는 것뿐만 아니라 스케일도 조정되어 그래프가 원 모양으로 바뀜


2-1. PCA  머신 러닝

# library import

from sklearn.decomposition import PCA


# PCA 모델 생성 및 적용

pca = PCA(n_components=100, whiten=True, random_state=0) # 주성분 갯수, whitening option, 랜덤상태

pca.fit(x_train) # PCA 학습

x_train_pca = pca.transform(x_train) # PCA를 데이터에 적용

x_test_pca = pca.transform(x_test)


# PCA를 적용한 데이터 형태

print('x_train_pca.shape \ntrain형태:{}'.format(x_train_pca.shape)) # (1547, 100)

print('x_test_pca.shape \ntest형태:{}'.format(x_test_pca.shape)) # (516, 100)


# 머신 러닝 모델 생성 및 학습

knn = KNeighborsClassifier(n_neighbors=1) # 이웃의 수

knn.fit(x_train_pca, y_train) # 모델 학습

print('테스트 세트 정확도: \n{:.3f}'.format(knn.score(x_test_pca, y_test))) # 0.314


모델의 정확도가 23%에서 31%로 상승


이미지 데이터일 경우엔 계산한 주성분을 쉽게 시각화 가능

주성분이 나타내는 것은 입력 데이터 공간에서의 어떤 방향임을 기억

입력 차원이 87 x 65픽셀의 흑백 이미지이고 따라서 주성분또한 87 x 65


print('pca.components_.shape \n{}'.format(pca.components_.shape)) # (100, 5655)


fig, axes = plt.subplots(3, 5, # subplot 3x5를 axes에 할당

                         subplot_kw={'xticks': (), 'yticks': ()}) # subplot 축 설정


for i, (comp, ax) in enumerate(zip(pca.components_, axes.ravel())): # pca.components_와 axes.ravel()을 하나씩 순서대로 할당한 후 인덱스 부여

    ax.imshow(comp.reshape(image_shape)) # image_shape= (87, 65)

    ax.set_title('pricipal component {}'.format(i+1)) # image title

plt.gray() # 사진 흑백

plt.show() # 사진 출력

얼굴 데이터셋의 pricipal component중 처음 15개


첫 번째 주성분은 얼굴과 배경의 명암차이를 기록한 것으로 추정

두번째 주성분은 오른쪽과 왼쪽 조명의 차이를 담고 있는 것으로 보임

이런 방식이 원본 픽셀 값을 사용하는 것보다 더 의미 있지만, 사람이 얼굴을 인식하는 방식과는 거리가 멈

알고리즘이 데이터를 해석하는 방식은 사람의 방식과는 상당히 다름


PCA 모델을 이해하기 위해 몇개의 주성분을 사용해 원본 데이터를 재구성

몇 개의 주성분으로 데이터를 줄이고 원래 공간으로 되돌릴 수 있음

원래 특성 공간으로 되돌리는 작업은 inverse_transform 메소드를 사용


mglearn.plots.plot_pca_faces(x_train, x_test, image_shape) # 훈련데이터, 테스트데이터, 이미지크기(87x65)

plt.gray() # 그림 흑백

plt.show() # 그림 출력

주성분 갯수에 따른 세 얼굴 이미지의 재구성



'python 머신러닝 -- 비지도학습 > PCA(주성분 분석)' 카테고리의 다른 글

PCA  (0) 2018.03.19

#!/usr/bin/env python3


preprocessing



0. 살펴보기

SVM과 neural_network는 데이터 스케일에 매우 민감

보통 특성마다 스케일을 조정해서 데이터를 변경


# library import

import mglearn

import matplotlib.pyplot as plt


mglearn.plots.plot_scaling() # 그래프 예제 출력

plt.show() # 그래프 출력


데이터셋의 스케일증 조정하거나 전처리하는 여러 방법


첫 번째 그래프는 두 개의 특성을 인위적으로 만든 이진 분류 데이터셋의


오른쪽의 4가지 그래프는 데이터를 기준이 되는 범위로 변환하는 방법

StandardScalar는 각 특성의 평균을 0, 분산을 1로 변경하여 모든 특성이 같은 크기를 가지게 함

    이 방법은 특성의 최솟값과 최댓값 크기를 제한하지 않음

RobustScaler는 특성들이 같은 스케일을 갖게 되지만 평균대신 중앙값을 사용 ==> 극단값에 영향을 받지 않음

MinMaxSclaer는 매우 다른 스케일의 범위를 0과 1사이로 변환

Nomalizer는 uclidian의 길이가 1이 되도록 데이터 포인트를 조정 ==> 각도가 많이 중요할 때 사용



1. 전처리를 통한 breast cancer 데이터 분석(SVM, Support Vector Machine)


# library import

from sklearn.datasets import load_breast_cancer

from sklearn.model_selection import train_test_split


# 데이터 로드

cancer = load_breast_cancer() 


# 데이터 분할

x_train, x_test, y_train, y_test = \ 

  train_test_split( # 데이터 분할을위해

      cancer.data, cancer.target, # 분할할 데이터

      test_size=0.25, random_state=1) # 테스트 비율, 랜덤상태


# 분할한 데이터 속성

print('x_train.shape \n{}'.format(x_train.shape))

print('x_test.shape \n{}'.format(x_test.shape))


# pre-processing import

# library import

from sklearn.preprocessing import MinMaxScaler


# 메소드 호출

scaler = MinMaxScaler() 



### MinMaxScaler의 fit 메소드는 train set에 있는 특성마다 최솟값과 최댓값을 계산 ###

### fit 메소드를 호출할 때 x_train만 넘겨줌 ###

scaler.fit(x_train) # 메소드 적용



###fit 메소드로 실제 훈련 데이터의 스케일을 조정하려면 스케일 객체의 transform 메소드를 사용 ###

### transform: 새로운 데이터 표현을 만들 때 사용하는 메소드 ###

# data 변환

x_train_scaled = scaler.transform(x_train)

x_test_scaled = scaler.transform(x_test)


# 스케일이 조정된 후 데이터셋의 속성

print('size: \n{}'.format(x_train_scaled.shape))

print('스케일 전 최솟값: \n{}'.format(x_train.min(axis=0))) # axis=0 열방향, axis=1 행방향

print('스케일 전 최댓값: \n{}'.format(x_train.max(axis=0)))

print('스케일 후 최솟값: \n{}'.format(x_train_scaled.min(axis=0))) # 최솟값 :0

print('스케일 후 최댓값: \n{}'.format(x_train_scaled.max(axis=0))) # 최댓값: 1


# 스케일이 조정된 후 테스트 데이터의 속성 출력

print('조정 후 특성별 최솟값: \n{}'.format(x_test_scaled.min(axis=0))) # 0이 최솟값이 아님

print('조정 후 특성별 최댓값: \n{}'.format(x_test_scaled.max(axis=0))) # 1이 최댓값이 아님



### 모든 스케일도 train set와 test set에 같은 변환을 적용해야 함 ###

### 스케일 조정된 데이터로 학습

# library import

from sklearn.svm import SVC


# 모델 생성 및 학습

svm = SVC(C=100)  

svm.fit(x_train, y_train)

svm_scaled = SVC(C=100).fit(x_train_scaled, y_train)


# 유효성 검증

print('조정 전 테스트 정확도 \n{:.3f}'.format(svm.score(x_test, y_test))) # 0.615

print('조정 후 테스트 정확도 \n{:.3f}'.format(svm_scaled.score(x_test_scaled, y_test))) # 0.965



### 스케일 조정된 데이터로 학습 ###

### 평균0, 분산 1을 갖도록 StandardScaler 조정 ###


# library import

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()

scaler.fit(x_train)

x_train_scaled = scaler.transform(x_train)

x_test_scaled = scaler.transform(x_test)


# 조정된 데이터로 SVM 학습

svm.fit(x_train_scaled, y_train) 


# 조정된 테스트 세트의 정확도

print('조정된 일반화 정확도 \n{:.3f}'.format(svm.score(x_test_scaled, y_test))) # 0.965


SVM은 스케일 조정에 민감하기때문에 결과값이 매우 다르게 나옴


#!/usr/bin/env python3

Neural Network(Deep Learning)

신경망이라 알려진 algorithm은 최근 deep learning이란 이름으로 불림
간단하게 Classifier와 Regression에 쓸 수 있는 multilayer perceptrons, MLP
multilayer perceptrons은 feed-forward, 또는 신경망이라고도 함

여러개의 가중치 합을 계산하는 것은 수학적으로 보면 하나의 가중치 합을 계산하는 것과 같음
각 은닉 유닛의 가중치 합을 계산한 후 그 결과에 비선형 함수인 rectified linear unit, ReLU나
hyperbolic tangent, tanh를 적용, 그 결과 가중치(𝘸)를 계산하여 ŷ 를 만듬

ReLu : 0이하를 잘라버리고,
tanh: x가 -∞일수록 -1, x가 ∞일수록 +1에 수렴

비선형 함수를 이용해 신경망이 선형 모델에서보다 훨씬 더 복잡한 함수를 학습 가능

1. ReLu함수와 tanh함수 살펴보기
# library import
import numpy as np
import matplotlib.pyplot as plt
import matplotlib

# matplotlib 설정
matplotlib.rc('font', family='AppleGothic'# 한글출력
plt.rcParams['axes.unicode_minus'] = False # 축 -설정

line = np.linspace(-3, 3, num=100) # 시작, 끝, 갯수
plt.plot( #  plot함수 호출
    line, np.tanh(line), linestyle='--',label='tanh' # x, y, style, label
    )
plt.plot(
    line, np.maximum(line, 0), label='relu'
    )
plt.xlabel('x'# x축 이름
plt.ylabel('tanh(x), relu(x)'# y축 이름
plt.legend(loc=2) # 범례위치 왼쪽 위
plt.show() # 그래프 출력

tanh(x), relu(x) 함수


2. Two moons Machine Learning(MLP, Multilayer perceptrons)
library load 
from sklearn.neural_network import MLPClassifier
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
import mglearn

# data load
x, y = make_moons( # moon data set 만들기
    n_samples=100, noise=0.25, random_state=3 # 갯수, 퍼짐정도, 랜덤상태
)

# data 분할
x_train, x_test, y_train, y_test = \
  train_test_split( # 데이터분할을 위해
      x, y, # 분할할 데이터
      stratify=y, random_state=42 # 그룹(binary 데이터로된 경우), 랜덤상태
      )

# model 생성 및 학습
mlp= MLPClassifier( # model 호출
    solver='lbfgs'# algorithm 
    random_state=42, # 랜덤 상태
    activation='relu', # 적용 함수
    hidden_layer_sizes=[100] # 은닉충 수 ex) [10 ,10] 유닛 10개짜리 은닉충 2개
    )
mlp.fit(x_train, y_train) # model 학습

# visualization
mglearn.plots.plot_2d_separator( # 2차원 데이터셋 분할 평면 그리기
    mlp, x_train, fill=True, alpha=0.3 # model 객체, train 데이터, 평면 칠하기, 투명도
    )
mglearn.discrete_scatter( # 2차원 산점도 그리기 위해
    x_train[:, 0], x_train[:, 1], y_train # x, y, 그룹
    )
plt.xlabel('feature 0'# x축 이름
plt.ylabel('feature 1'#  y축 이름
plt.show() # 그래프 출력

은닉 유닛이 100개인 neural로 학습한 two_moons 데이터셋의 결정 경계


neural_network는 매우 비 선형적이지만 비교적 매끄러운 decision boundary

3. Regularization 과 Visualization
Ridge Regression과 Linear Classifier에서 처럼 L2 penalty(계수를 0에 근접)로 alpha로 모델의 복잡도를 제어
기본값은 0.0001

# visualization
fig, axes = plt.subplots(2, 4) # figure객체를 fig에, plots객체를 axes에 2X4만큼 할당
n_hidden_nodes = [10, 100] # 배열생성
alpha_set = [0.0001, 0.01, 0.1, 1] # 배열 생성
for axe, n_node in zip(axes, n_hidden_nodes): # axes(2X4를 1X4, 1X4)와 n_hidden_nodes를 하나씩 axe와 n_node에 할당
    for ax, alpha in zip(axe, alpha_set): # axe(1X4)와 alpha_set을 하나씩 ax와 alpha에 할당
        mlp = MLPClassifier( # model 생성을 위해
            solver='lbfgs'# algorithm
            random_state=42, # 랜덤 상태
            hidden_layer_sizes=[n_node, n_node], # 은닉충
            alpha=alpha # 규제정도(클수록 강화)
            )
        mlp.fit(x_train, y_train) # 학습
        mglearn.plots.plot_2d_separator(# 2차원 평면을 나누기 위해
            mlp, x_train, # model 객체, train데이터
            fill=True, alpha=0.3, ax=ax # 평면칠하기, 투명도, plot객체
            )
        mglearn.discrete_scatter( # 2차원 산점도 그래프를 위해
            x_train[:, 0], x_train[:, 1], y_train, ax=ax # x, y, 그룹, plot객체
            )
        ax.set_title('n_hidden=[{}, {}]\nalpha={}'.format( # 타이틀
            n_node, n_node, alpha
            ))
plt.show()

은닉 유닛과 alpha에 따라 변하는 decision boundary


4. Breast Cancer Dataset Machine Learning(MLPClassifier)
# load library
from sklearn.datasets import load_breast_cancer
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import matplotlib

# matplotlib 설정
matplotlib.rc('font', family='AppleGothic'# 한글 설정
plt.rcParams['axes.unicode_minus'] = False # -표시

# data load
cancer = load_breast_cancer()

# data  분할
x_train, x_test, y_train, y_test = \
  train_test_split( # 데이터 분할을 위해
      cancer.data, cancer.target, # 분할할 데이터
      random_state=0, test_size=0.3 # 랜덤상태, 테스트 비율
      )

# feature visualization
plt.boxplot(x_train, manage_xticks=False) # 데이터, 소눈금 표시 안하기
plt.yscale('symlog') # 축 스케일을 log 로
plt.xlabel('feature list'# x축 이름
plt.ylabel('feature'# y축 이름
plt.show() # 그래프 출력

breast cancer 데이터셋의 특성 값 범위(y축은 logscale)


# 전처리, pre-processing
# axis =0 ==> 열, axis =1 ==> 행
train_min = x_train.min(axis=0) # 열방향 최솟값
train_range = (x_train - train_min).max(axis=0) # 최솟값을 제거한 후 최댓값

x_train_scaled = (x_train-train_min)/train_range # train data 조정
x_test_scaled = (x_test-train_min)/train_range # test data 조정(train 데이터 범위로 조정)

x_train_scaled.min(axis=0) # 조정된 범위의 최솟값, 0
x_train_scaled.max(axis=0) # 조정된 범위의 최댓값, 1

print('x_train_scaled min \n{}'.format(x_train_scaled.min(axis=0))) # 0
print('x_train_scaled.max \n{}'.format(x_train_scaled.max(axis=0))) # 1

# model  생성 및 학습
mlp = MLPClassifier( # model 생성
    solver='lbfgs', # algorithm
    random_state=0, # 랜덤상태
    hidden_layer_sizes=[100], # 은닉층 수
    alpha=0.001 # 규제 정도
    )
mlp.fit(x_train_scaled, y_train) # 학습

mlp.score(x_train_scaled, y_train) # train set 정확도
mlp.score(x_test_scaled, y_test) # 일반화 정확도

print('train set scaled accuracy \n{:.3f}'.format(mlp.score(x_train_scaled, y_train))) # 1.000
print('test set sclaed accuracy \n{:.3f}'.format(mlp.score(x_test_scaled, y_test))) # 0.965

5. Breast Cancer 데이터셋으로 학습된 가중치 확인
행 : 30개의 입력특성
열 : 100개의 은닉 유닛
밝은 색은 큰 양수 값

plt.figure(figsize=(20, 5)) # 그림 size
plt.imshow(
    mlp.coefs_[0], interpolation='none', cmap='viridis' # 입력과 은닉층 사이의 가중치, 축, 그림 테마
    )
plt.yticks(range(30), cancer.feature_names) # y축 포인트, label
plt.xlabel('은닉 유닛') # x축 이름
plt.ylabel('입력 특성') # y축 이름
plt.colorbar() # colorbar 생성
plt.show() # 그래프 출력

breast cancer 데이터셋으로 학습시킨 신경망의 첫번째 층의 가중치 히트맵


mlp.coefs_[0]은 입력과 은닉충 사이의 가중치가 저장되어있는 (30, 100) NumPy배열이고
mlp.coefs_[1]은 은닉충과 출력사이의 가중치가 저장되어있는 (100, 1) 크기의 NumPy배열



'python 머신러닝 -- 지도학습 > Classifier' 카테고리의 다른 글

Kernelized Support Vector Machines  (0) 2018.03.15
Gradient Boosting Model  (0) 2018.03.15
Random Forest  (0) 2018.03.15
Decision Tree  (0) 2018.03.14
Multi Linear Classification  (0) 2018.03.14

/usr/bin/env python3


Kernelized Support Vector Machine


데이터가 단순한 초평면으로 구분되지 않는 더 복잡한 model을 만들 수 있도록 확장한 것이

Kernelized Support Vector Machine입니다.


선형적으로 구분되지 않는 클래스를 가진 binary data 생성하여 시각화해보겠습니다.

from mglearn.datasets import make_blobs

from sklearn.svm import LinearSVC

from mglearn.plots import plot_2d_separator

import matplotlib.pyplot as plt

import numpy as np


x, y = make_blobs(centers=4, random_state=8)

y = y % 2 # y를 binary화


linear_svm = LinearSVC().fit(x, y) 


plot_2d_separator(linear_svm, x, fill=False)


marker_set = ['o', '^']

for i, m in zip(np.unique(y), marker_set):

    plt.scatter(x[y==i][:, 0], x[y==i][:, 1], marker=m,

                label='class {}'.format(i), edgecolors='k')

plt.legend(bbox_to_anchor=(0.1, 1.1), fancybox=True)

plt.xlabel('feature 0', size=15)

plt.ylabel('feature 1', size=15)

plt.show()

선형적으로 구분되지 않는 클래스를 가진 binary data

이런 경우에는 Kernel Support Vector Machine를 사용할 수 있습니다.

support vector machine에서 데이터를 고차원 공간에 매핑하는 방법은 크게 2가지가 있으며


1. 원래 특성의 가능한 조합을 모두 계산((특성1)^2, (특성2)^5) 하거나

2. (radial basis function), RBF커널-- 가우시안 커널을 사용하는 것입니다.

RBF 커널의 경우 특성의 중요도는 테일러급수를 이용하기때문에 고차원일수록 줄어듭니다.



1번 방법으로 고차원 공간에 매핑하겠습니다.

# 선 하나로 구분되지 않는 데이터를 분석하기 위해 수학적방법으로 차수를 하나 늘려 비선형 데이터축 추가합니다.


# x[:, 1:]

# x[:, 1].reshape(-1, 1)

# x[:, 1][:,np.newaxis]

# 위의 3개는 모두 같은 결과입니다.

x_new = np.hstack([x, x[:, 1:]**2])


linear_svm_3d = LinearSVC().fit(x_new, y)


xx = np.linspace(x[:, 0].min()-2, x[:, 0].max()+2, num=50)

yy = np.linspace(x[:, 1].min()-2, x[:, 1].max()+2, num=50)


# xx, yy의 좌표를 이용하여 교차 좌표 만듬 ex) x=[1, 2], y=[3, 4]라면 (1, 3), (1, 4), (2, 3), (2, 4) 좌표 생성합니다.

XX, YY = np.meshgrid(xx, yy)

ZZ = YY ** 2 


params = np.c_[XX.ravel(), YY.ravel(), ZZ.ravel()] # np.c_ : XX, YY, ZZ의 원소를 하나씩 출력하여 한개의 행으로 묶기

dec = linear_svm_3d.decision_function(params)

plt.contourf(XX, YY, dec.reshape(XX.shape), # XX.shape = (50, 50) 

             levels=[dec.min(), 0, dec.max()],

                 alpha=0.5)


for i, m in zip(np.unique(y), marker_set):

    plt.scatter(x[y==i][:, 0], x[y==i][:, 1], marker=m, edgecolors='k')


plt.xlabel('feature 0', size=15)

plt.ylabel('feature 1', size= 15)

plt.show() 

고차원 특성을 이용해 구분한 Support vector machine decision boundary



Support Vector는 학습이 진행되는 동안 SVM은 각 train 데이터 포인트가 두 class 사이의 decision boundary를 구분하는 데 얼마나 중요한지를 배우게 됩니다.

일반적으로 train 데이터의 일부만 decision boundary를 만드는데 영향을 줍니다.


class 두 개의 경계에 위치한 데이터 포인트를 support vector라 합니다.


suppor vector의 중요도는 train 과정에서 학습하며 SVC객체의 dual_coef_에 저장되며

radial basis function, RBF커널, gaussian  : 특성의 중요도는 테일러급수를 이용하기때문에 고차원일수록 줄어듭니다.

이번에는 원래 2개 특성의 투영한 decision boundary를 그려보겠습니다.

from sklearn.svm import SVC

from mglearn.tools import make_handcrafted_dataset

from mglearn.plots import plot_2d_separator


x, y = make_handcrafted_dataset()


svm = SVC(kernel='rbf', C=10, gamma=0.1) # kernel, 규제정도, 커널폭의 역수

svm.fit(x, y)


plot_2d_separator(svm, x, eps=0.5)  # epsilon


marker_set = ['o', '^']

color_set = ['skyblue', 'orange']

class_set = np.unique(y)

for i, m, color in zip(class_set, marker_set, color_set):

    plt.scatter(x[y==i][:, 0], x[y==i][:, 1], marker=m, 

label='class {}'.format(i), edgecolors='k', c=color)


sv = svm.support_vectors_

print('{}'.format(sv))

# [[ 8.1062269   4.28695977]

#  [ 9.50169345  1.93824624]

#  [11.563957    1.3389402 ]

#  [10.24028948  2.45544401]

#  [ 7.99815287  4.8525051 ]]


# dual_coef_의 부호에 의해 서포트 벡터의 클래스 레이블이 결정됩니다.

sv_labels = svm.dual_coef_.ravel() > 0 # 중요도가 0보다 높은  것, 클래스 구분

idx_set = [~sv_labels, sv_labels]


for idx,m, color in zip(idx_set, marker_set, color_set):

    plt.scatter(sv[idx][:, 0], sv[idx][:, 1],  s=100, 

marker=m, edgecolors='k', linewidths=2, c=color)


plt.xlabel('feature 0', size=15)

plt.ylabel('feature 1', size=15) 

plt.show() 

RBF Kernel을 사용한 SVM으로 만든 decision boundary와 support vector




SVM에서 model의 complexity를 제어하는 주요 parmeter

gamma: kernel폭의 역수입니다.

gamma가 작을 수록 knernal폭이 넓어져 train 데이터의 영향 범위도 넓어집니다.


다음은 C와 gamma에 따른 decision area를 보여줍니다.

fig, axes = plt.subplots(3, 3) 


C_args = np.array([-1, 0, 3])

C_set = 10**C_args.astype(float)


gamma_args = np.arange(-1, 2)

gamma_set = 10**gamma_args.astype(float)


marker_set = ['o', '^']

for axe, C in zip(axes, C_set):

    for ax, gamma in zip(axe, gamma_set):

        params = {'C':C, 'gamma':gamma}


        svm = SVC(**params).fit(x, y)


        plot_2d_separator(svm, x, eps=0.5, ax=ax)

        ax.set_title('C={}, gamma={}'.format(C, gamma))


        color_set = ['skyblue', 'orange']

        for i, m, color in zip(np.unique(y), marker_set, color_set):

            ax.scatter(x[y==i][:, 0], x[y==i][:, 1], marker=m,

                       label='class {}'.format(i), c=color, edgecolors='k')


        sv = svm.support_vectors_

        idx = svm.dual_coef_.ravel() < 0

        idx_set = np.array([idx, ~idx])


        for i, idx, color, m in zip(np.unique(y), idx_set, color_set, marker_set):

            ax.scatter(sv[idx][:, 0], sv[idx][:, 1], marker=m,

                       c=color, label='class {} support vector'.format(i), s=100,

                       edgecolors='k', linewidths=2)

        

axes[0, 1].legend(loc='upper center', bbox_to_anchor=(0.5, 1.4), fancybox=True, shadow=True, ncol=4)

plt.show()

C와 gamma 에 따른 decision boundary와 support vector

왼쪽에서 오른쪽으로 가면서 gamma 0.1 -> 10 으로 증가합니다.

작은 gamma는 gaussia kernel의 반경을 크게 하여 많은 포인트들이 가까이 있는 것으로 고려됩니다.

따라서 왼쪽 그림의 decision boundary는 부드럽지만 오른쪽 그림의 decision boundary는 데이터 포인트 하나에 민감합니다.

gamma의 값이 클수록 model의 복잡도가 올라가는 것을 확인할 수 있습니다.


위에서 아래로는 C 값을 0.1 -> 1000으로 증가합니다.

linear model과 마찬가지로 작은 C값은 제약이 큰 model을 만듭니다. ==> 일반화 성능이 증가


C값을 증가시키면 제약이 거의 없어져 포인트 하나 값에 영향이 커집니다. ==> 복잡도 증가



SVM으로 Wine Data를 분석해보겠습니다. 

from sklearn.model_selection import train_test_split

from sklearn.datasets import load_wine

from sklearn.svm import SVC


wine = load_wine()


x_train, x_test, y_train, y_test = train_test_split(

      wine.data, wine.target, stratify=wine.target,

      random_state=0, test_size=0.25)


svc = SVC(random_state=0) # default: C=1, kernel='rbf', gamme='auto'

svc.fit(x_train, y_train) 


train_score = svc.score(x_train, y_train)

test_score = svc.score(x_test, y_test)


print('{:.3f}'.format(train_score))

# 1.000


print('{:.3f}'.format(test_score))

# 0.422

gamma의 기본값은 auto로 : 1/wine.data.shape[1]입니다.

train set는 완벽하지만 일반화는 42.2%의 정확도로 overfitting된 것을 알 수가 있습니다.



SVM은 parameter설정과 data scale에 매우 민감합니다. 이를 해결하기 위해 data preprocessing이 존재합니다.

preprocessing을 하기 전에 wine data의 특성을 시각화하여 알아보겠습니다.

plt.boxplot(x_train, manage_xticks=False) # manage_xticks: x축 눈금 작은 눈금 표시

plt.yscale('symlog') # y축 로그 스케일

plt.xlabel('feature list', size =15

plt.ylabel('feature size', size =15)

plt.show()

wine 데이터셋의 특성 값 범위(y축은 logscale)

그래프를 보면 wine 데이터셋의 특성은 자릿 수 자체가 달라서 SVM에서는 영향이 아주 큼을 알 수 있습니다.



이제는 SVM을 위한 데이터 전처리를 해보겠습니다.

전처리는 특성 값의 범위가 비슷해지도록 조정하는 것입니다.


모든 특성의 값을 0과 1사이로 맞추는 방법을 많이 사용합니다.

train_min = x_train.min(axis=0) 

train_range = (x_train - train_min).max(axis=0)

x_train_scaled = (x_train - train_min) / train_range

x_test_scaled = (x_test - train_min) / train_range

    

x_min_ori = x_train_scaled.min(axis=0)

print('{}'.format(x_min_ori))

# [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]


x_max_ori = x_train_scaled.max(axis=0)

print('{}'.format(x_max_ori))

# [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]



위의 코드는 아래와 같이 전처리 메소드를 로드하여 사용할 수 있으며 앞으로는 이 방법을 사용하겠습니다.

from sklearn.preprocessing import MinMaxScaler


mms_scaler = MinMaxScaler()

mms_scaler.fit(x_train)


x_train_scaled_mms = mms_scaler.transform(x_train)

x_test_scaled_mms = mms_scaler.transform(x_test)


x_min = x_train_scaled.min(axis=0)

print('{}'.format(x_min))

# [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]


x_max = x_train_scaled.max(axis=0)

print('{}'.format(x_max))

# [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]



이제 전처리한 데이터로 머신러닝을 해보겠습니다.

svc = SVC(random_state=0)

svc.fit(x_train_scaled_mms, y_train)


train_score = svc.score(x_train_scaled_mms, y_train)

test_score = svc.score(x_test_scaled_mms, y_test)


print('{:.3f}'.format(train_score))

# 0.970


print('{:.3f}'.format(test_score))

# 0.978

스케일을 조정하니 성능이 매우 좋아졌습니다.



이번에는 C값을 매우 크게 하여 규제를 완화 해보겠습니다.

svc = SVC(C=1000) 

svc.fit(x_train_scaled, y_train) 


train_score = svc.score(x_train_scaled_mms, y_train) 

test_score = svc.score(x_test_scaled_mms, y_test)


print('{:.3f}'.format(train_score))

# 1.000


print('{:.3f}'.format(test_score))

# 1.000

규제를 매우 완화 하니 train_score와 test_score모두 결과가 1이 나와 과소적합된 형태입니다.



SVM은 데이터의 특성이 몇개 안되도 복잡한 decision boundary를 만들 수 있습니다.

SVM은 parameter와 pre-procession(전처리)에 신경을 많이 써야합니다.


random_forest나 gradient boosting 같은 pre-processing이 거의 없는 모델을 많이 사용합니다.

그러나 예측이 어떻게 결정되었는지 이해하기 어렵고 비전문가에게 설명하기또한 난해합니다.




참고 자료:

[1]Introduction to Machine Learning with Python, Sarah Guido

'python 머신러닝 -- 지도학습 > Classifier' 카테고리의 다른 글

Neural Network(Deep Learning)  (0) 2018.03.17
Gradient Boosting Model  (0) 2018.03.15
Random Forest  (0) 2018.03.15
Decision Tree  (0) 2018.03.14
Multi Linear Classification  (0) 2018.03.14

#!/usr/bin/env python3


Ridge


Ridge는 linear model이므로 OLS(Ordinary Least Square)를 사용합니다.

Ridge Regression에서 가중치(w) 선택은 추가 제약 조건을 생성하여

가중치(w)의 절댓값을 가능학 작게 만드는 것(0으로 만드는 것이 아님)입니다.


기하학적으로 모든 특성의 기울기를 0에 가깝게 만드는 것이고 이 것을 regularization이라 합니다.

즉 model을 overfitting 하지 않도록 강제로 제한하는 것입니다.


Ridge Regression에 사용하는 regularization을 L2 regularization이라고도 합니다.


보스턴 주택가격으로 Ridge Regression과 linear regression을 사용하여 비교해보겠습니다.

from mglearn.datasets import load_extended_boston

from sklearn.linear_model import Ridge, LinearRegression

from sklearn.model_selection import train_test_split


boston_data, boston_target = load_extended_boston()

x_train, x_test, y_train, y_test = \

  train_test_split(boston_data, boston_target,

                   random_state=0, test_size=0.3)


ridge = Ridge()

ridge.fit(x_train, y_train)

lr = LinearRegression()

lr.fit(x_train, y_train)


print('{:.3f}'.format(ridge.score(x_train, y_train)))

# 0.882

print('{:.3f}'.format(lr.score(x_train, y_train)))

# 0.952

print('{:.3f}'.format(ridge.score(x_test, y_test)))

# 0.783

print('{:.3f}'.format(lr.score(x_test, y_test)))

# 0.645

train set정확도는 Ridge Reg. < Linear Reg.

test set정확도는 Ridge Reg. > Linear Reg. 입니다.


Linear Reg는 train set과 test set의 차이가 많이나므로 overfittng이 되지만

Ridge Reg는 regularization이 적용되기 때문에 train set과 test set의 차이가 적습니다.

따라서 model의 complexity가 낮아지게 되고 test set의 정확도는 상승합니다.



다음으로 Ridge의 Regularization에 대해서 알아보겠습니다.

Ridge Reg.는 alpha parameter로 model을 얼마나 단순화할지를 결정합니다.

default 값은 1이며 높을수록 Regularization을 강화하여 계수를 0에 가깝게 만듭니다.


alpha값에 따른 정확도비교는 아래코드로 확인할 수 있습니다.

alpha_train_score = []

alpha_test_score = []

alpha_set = [0.1, 1 ,10]


for i in alpha_set:

    ridge=Ridge(alpha=i)

    ridge.fit(x_train, y_train)


    ridge_tr_score = round(ridge.score(x_train, y_train), 3)

    ridge_te_score = round(ridge.score(x_test, y_test), 3)


    alpha_train_score.append(ridge_tr_score)

    alpha_test_score.append(ridge_te_score)


print(alpha_set)

# [0.1, 1, 10]


print(alpha_train_score)

# [0.927, 0.882, 0.78]


print(alpha_test_score)

# [0.797, 0.783, 0.678]

alpha값이 커질수록(규제가 강화될수록) 정확도는 낮아지는 것을 볼 수 있습니다.



Ridge도 Linear_model이므로 속성(coef_, intercept_)가 존재합니다.

Ridge의 alpha값에 따른 coef_를 조사하면

import numpy as np

import matplotlib.pyplot as plt


n_feature = boston_data.shape[1]

line = np.linspace(0, n_feature, num=n_feature).reshape(-1, 1)


lr = LinearRegression().fit(x_train, y_train)

plt.scatter(line, lr.coef_, marker='s', label='Linear Reg.') # marker = 's'  => square


alpha_set = [0.1, 1 ,10]

marker_set = ['o', '^', 'v']

for i, m in zip(alpha_set, marker_set):

    ridge = Ridge(alpha=i)

    ridge.fit(x_train, y_train)

    plt.scatter(line, ridge.coef_, marker=m, label='alpha={}'.format(i))


plt.ylim(-30, 30)

plt.hlines(y=0, xmin=0, xmax=n_feature)

plt.legend(loc=(0.01, 1.01))

plt.show()

Linar Regression과 몇 가지 alpha 값을 가진 Ridge Regression의 coefficient 비교

x축은 coef_의 원소를 위치대로 나열한 것입니다. 즉 x=0, x=1은 각각 첫번째 특성과 두번째 특성을 나타내는 것입니다.

alpha=10일 때(빨강 역삼각형)은 대부분 y=0에 위치하며

alpha=1(초록 정삼각형)은 alpha=10일 때보다는 약간 퍼진 상태입니다.

alpha=0.1(주황 원)은 매우 크게 확장되었으며

Linear Reg.(파랑 정사각형)은 자유롭게 퍼져있는 것을 확인할 수 있습니다.



이번엔 learning curve(데이터셋의 크기에 따른 모델의 성능 변화)를 알아보겠습니다.

train_ridge_set = []

train_linear_set = []

test_ridge_set = []

test_linear_set = []


for i in test_size_set:

    x_train, x_test, y_train, y_test = \

      train_test_split(boston_data, boston_target,

                       random_state=35, test_size=i)

    ridge = Ridge(alpha=1).fit(x_train, y_train)

    lr = LinearRegression(n_jobs=-1).fit(x_train, y_train) # n_jobs = 사용할 코어의 수, -1은 모든 코어사용


    rid_tr_score = ridge.score(x_train, y_train)

    rid_te_score = ridge.score(x_test, y_test)

    lr_tr_score = lr.score(x_train, y_train)

    lr_te_score = lr.score(x_test, y_test)


    train_ridge_set.append(rid_tr_score)

    train_linear_set.append(lr_tr_score)

    test_ridge_set.append(rid_te_score)

    test_linear_set.append(lr_te_score)


plt.plot(x_ticks, train_ridge_set, c='lightblue', ls='--', label='train ridge'# c = color, ls = linestyle

plt.plot(x_ticks, train_linear_set, c='orange', ls='--',label='train Linear_Reg')

plt.plot(x_ticks, test_ridge_set, c='lightblue', label='test ridge')

plt.plot(x_ticks, test_linear_set, c='orange', label='test Linear_Reg')


plt.legend(loc=(0.01, 1.01))

plt.ylim(0, 1.1)

plt.show()

보스턴 주택가격 데이터셋에 대한 Ridge vs Linear Reg,

train 데이터(점선)가 test 데이터(line)보다 높음을 알 수 있습니다.

Ridge에는 regularization이 적용되므로 Linear Reg보다 낮습니다.


일반화 데이터에서는 Ridge의 점수가 더 높으며, 데이터셋이 작을수록 두드러집니다.

데이터셋의 크기가 작을수록 Linear Reg.는 어떤 것도 학습하지 못합니다.


데이터가 충분히 크면 regularization이 덜 중요해지고(두 모델의 차이가 줄어듭니다.)

Linear_Reg의 경우 데이터셋이 클수록 train 데이터 성능이 감소합니다. 이는 데이터가 많아질수록 overfitting 하기가 어려움을 시사합니다




참고 자료: 

[1]Introduction to Machine Learning with Python, Sarah Guido

'python 머신러닝 -- 지도학습 > Regression' 카테고리의 다른 글

Decision Tree Regressor  (0) 2018.03.14
Lasso  (0) 2018.03.13
LinearRegression  (0) 2018.03.12
k_NN(k-최근접 이웃) Regression  (1) 2018.03.12

+ Recent posts