#!/usr/bin/env python3


TensorFlow Way of LinearRegression




이번 예제에서는 tensorflow를 통해 일괄적으로 데이터에 대한 루프를 돌면서 기울기와 y절편을  갱신할 것입니다.

Petal width꽃잎 폭을 x로 Sepal length길이를 y로하는 데이터를 대상으로 최적 직선을 찾아보겠습니다. L2 비용 함수를 사용하겠습니다.


iris데이터셋으로 Linear Regression을 해결하기 위해서는 역시 아래 방정식을 풀어야 합니다.

$$y = Ax+b$$


linear regression computational graph를 사용하기 위해서서는 input으로 $x$ 를 넣었을 때, 

$Ax+b$가 만들어져야 하고 $A$, $b$는 손실값이 최소가 되어야 합니다.

import numpy as np

import tensorflow as tf

from sklearn.datasets import load_iris

from tensorflow.python.framework import ops


iris = load_iris()


print(iris.keys())

# dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])


print(iris.feature_names)

# ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']


x_vals = np.array([x[3] for x in iris.data])

y_vals = iris.data[:,0]


batch_size = 25


x_data = tf.placeholder(shape=[None, 1], dtype=tf.float32)

y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)


A = tf.Variable(tf.random_normal(shape=[1, 1]))

b = tf.Variable(tf.random_normal(shape=[1, 1]))



데이터가 준비되었으니 tensorflow 방식으로 algorithm을 구현하면 다음과 같습니다.

with tf.Session() as sess:

    model_output = tf.add(tf.matmul(x_data, A), b) # linear regression fomula

    loss = tf.reduce_mean(tf.square(y_target - model_output)) # L2 loss

    my_opt = tf.train.GradientDescentOptimizer(learning_rate=0.05) 

    train_step = my_opt.minimize(loss) # loss가 최소인 방향으로 다음 단계 이동


    init = tf.global_variables_initializer()

    init.run()


    loss_vec = []

    for i in range(100):

        rand_idx = np.random.choice(len(x_vals), size=batch_size) 

        rand_x = x_vals[rand_idx].reshape(-1, 1)

        rand_y = y_vals[rand_idx].reshape(-1, 1)


        fedict={x_data: rand_x, y_target:rand_y}


        sess.run(train_step, feed_dict=fedict) # step 반복

        temp_loss = sess.run(loss, feed_dict=fedict)

        loss_vec.append(temp_loss)


        if (i+1)%20==0:

            print('Step {}\nA={}, b={}   Loss={:.5f}'.format(i+1, A.eval(), b.eval(), temp_loss))

            # Step 20

            # A=[[2.4062862]], b=[[2.4534268]]   Loss=1.78677

            # Step 40

            # A=[[1.9556967]], b=[[3.2615643]]   Loss=0.92836

            # Step 60

            # A=[[1.5368886]], b=[[3.698664]]   Loss=0.53148

            # Step 80

            # A=[[1.4006948]], b=[[4.085002]]   Loss=0.46051

            # Step 100

            # A=[[1.1938996]], b=[[4.331669]]   Loss=0.31104


    [slope] = A.eval()

    print('slope: {}'.format(slope))

    # slope: [1.1938996]


    [cept] = b.eval()

    print('intercept: {}'.format(cept))

    # intercept: [4.331669]



위의 결과를 시각화하는 코드는 다음과 같습니다.

import matplotlib.pyplot as plt


best_params = []

for i in x_vals.ravel():

    poly = i*slope+cept

    best_params.append(poly)


plt.scatter(x_vals, y_vals, label='Data Points', edgecolors='k')

plt.plot(x_vals, best_params, 'red')

plt.xlabel('Petal Width', size=15)

plt.ylabel('Sepal Length', size=15)

plt.title('Petal Width vs Sepal Length')

plt.show()



plt.plot(loss_vec, c='k')

plt.xlabel('Generation')

plt.ylabel('L2 Loss')

plt.title('L2 Loss per Generation')

plt.show()





참고 자료: 

[1]TensorFlow Machine Learning Cookbook, Nick McClure

[2]https://github.com/nfmcclure/tensorflow_cookbook


#!/usr/bin/env python3


Using the Cholesky Decomposition Method


Linear Regression은 $A \cdot x=y$을 사용합니다. 

Cholesky decomposition은 matrix $A$를 lower triangular matrix $L$과 $L^{T}$로 분해합니다.

차원을 같게 하기 위해 matrix $A$ 앞에 $A^{T}$를 곱하여 square matrix로 만듭니다.

따라서 아래와 같은 식이 성립합니다.

$A^{T} \cdot A=L^{T} \cdot L$


Linear Regression을 적용하면 아래와 같이 사용할 수 있습니다.

$A\cdot X=Y$

$(A^{T} \cdot A) \cdot X = A^{T} \cdot Y$

$(L^{T} \cdot L) \cdot X = A^{T} \cdot Y$

$L^{T} \cdot Z = A^{T} \cdot Y$,     $L \cdot X = Z$


Cholesky decomposition을 Linear Regression에 적용하기 위해서는 다음과 같은 step이 필요합니다.

1. $A^{T} \cdot A = L^{T} \cdot L$에서 $L$을 구합니다.

2. $L^{T} \cdot Z = A^{T} \cdot Y$에서 $Z$를 구합니다.

3. $L \cdot X = Z$에서 $X$를 구합니다.


$X$는 우리가 구하고자 하는 slope와 intercept가 있는 matrix입니다.


이 과정을 간단한 데이터를 만들어 구현해 보겠습니다.

import tensorflow as tf

import numpy as np


x_vals = np.linspace(0, 10, 100).reshape(-1, 1)

print(x_vals[:6])

# [[0.        ]

#  [0.1010101 ]

#  [0.2020202 ]

#  [0.3030303 ]

#  [0.4040404 ]

#  [0.50505051]]


y_vals = x_vals + np.random.normal(0, 1, size=100).reshape(-1, 1)

print(y_vals[:6])

# [[-1.34770577]

#  [-0.4146378 ]

#  [-0.14096172]

#  [ 0.23305495]

#  [ 1.66821972]

#  [-0.35141322]]


ones = np.ones(100).reshape(-1, 1)

print(ones[:6])

# [[1.]

#  [1.]

#  [1.]

#  [1.]

#  [1.]

#  [1.]]


A = np.c_[x_vals, ones]

print(A[:6])

# [[0.         1.        ]

#  [0.1010101  1.        ]

#  [0.2020202  1.        ]

#  [0.3030303  1.        ]

#  [0.4040404  1.        ]

#  [0.50505051 1.        ]]


A_tsr = tf.constant(A, dtype=tf.float32)

y_tsr = tf.convert_to_tensor(y_vals, dtype=tf.float32)


with tf.Session() as sess:

    tA_A = tf.matmul(tf.transpose(A_tsr), A_tsr)

    L = tf.cholesky(tA_A)

    

    # solve $L\cdot Z=A^{T}  \cdot Y$, for $Z$

    tA_y = tf.matmul(tf.transpose(A_tsr), y_tsr)

    sol1 = tf.matrix_solve(L, tA_y)

    

    # solve $L^{T} \cdot X= Z$,  $Z$=sol1,  for $X$

    sol2 = tf.matrix_solve(tf.transpose(L), sol1)

    solution = sol2.eval()


slope = solution[0][0]

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

# slope: 0.988516


cept = solution[1][0]

print('intercept: {:.3f}'.format(cept))

# intercept: 0.163



시각화는 다음코드로 구현할 수 있습니다.

import matplotlib.pyplot as plt


reg_params = []

for i in x_vals.ravel():

    poly = i*slope + cept

    reg_params.append(poly)

    

plt.scatter(x_vals, y_vals, label='data')

plt.plot(x_vals, reg_params, c='red', label='best fit line')

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

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

plt.legend(loc='upper center', bbox_to_anchor=[0.1, 1.1], fancybox=True)

plt.show()

Cholesky 분해로 분석한 LinearRegression




참고 자료: 

[1]TensorFlow Machine Learning Cookbook, Nick McClure

[2]https://github.com/nfmcclure/tensorflow_cookbook

'Tensorflow > Linear Regression' 카테고리의 다른 글

LASSO and Ridge Regression  (1) 2018.04.27
Deming Regression  (0) 2018.04.27
Loss Function in Linear Regressions  (0) 2018.04.26
TensorFlow Way of LinearRegression  (0) 2018.04.26
Inverse Matrix Method  (0) 2018.04.26

#!/usr/bin/env python3


Inverse Matrix Method


일반적인 linear regression의 식은 다음과 같이 쓸 수있습니다.

$ y = ax + b $, 그러나 이 식을 행렬로 확장하면 $AX = Y$로 쓸 수 있습니다.

$$X=A^{-1}(A^{-T}A^{T})Y$$

$$X=(A^{T}A)^{-1}A^{T}Y$$


$$A = \left[ {\begin{array}{cc}   x_{ 11 } & x_{ 12 } & x_{ 13 } & \cdots  & 1 \\  x_{ 21 } & x_{ 22 } & x_{ 23 } & \cdots  & 1 \\  \vdots&\vdots   &\vdots  &\ddots   & \vdots \\x_{ 31 } & x_{ 32 } & x_{ 33 } & \cdots  & 1 \end{array} } \right]$$


$$ point_{i}=(y_{i}, x_{i1}, x_{i2}, \cdots, x_{iF})$$


간단한 데이터를 만들어 이를 구현해보겠습니다.

import tensorflow as tf

import numpy as np


x_vals = np.linspace(0, 10, 100).reshape(-1, 1)

y_vals = x_vals + np.random.normal(0, 1, size=100).reshape(-1, 1)

ones = np.ones(100).reshape(-1, 1)


A = np.c_[x_vals, ones]


A_tsr = tf.constant(A, dtype=tf.float32)

y_tsr = tf.convert_to_tensor(y_vals, dtype=tf.float32)


init = tf.global_variables_initializer()

with tf.Session() as sess:

    init.run()

    tA_A = tf.matmul(tf.transpose(A_tsr), A_tsr)

    tA_A_inv = tf.matrix_inverse(tA_A)

    prod = tf.matmul(tA_A_inv, tf.transpose(A_tsr))

    sol = tf.matmul(prod, y_tsr)

    solution = sol.eval()


slope = solution[0][0]

cept = solution[1][0]


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

# slope :1.000


print('intercept :{:.3f}'.format(cept))

# intercept :0.012



이 결과를 시각화하는 코드는 다음과 같습니다.

import matplotlib.pyplot as plt


reg_params = []

for i in x_vals.ravel():

    poly = slope*i + cept

    reg_params.append(poly)


plt.scatter(x_vals, y_vals, c='orange')

plt.plot(x_vals, reg_params, c='blue', lw=2)

plt.show()

inverse matrix를 이용한 Linear Regression

이런 방법은 데이터셋이 커지게 되면 느려진다는 단점이 있습니다.




참고 자료: 

[1]TensorFlow Machine Learning Cookbook, Nick McClure

[2]https://github.com/nfmcclure/tensorflow_cookbook

#!/usr/bin/env python3


Operations on a Computational Graph, Layering Nested Operations


placeholder에 넣을 데이터를 만들고, 상수를 곱해보겠습니다.

import tensorflow as tf

import numpy as np

from tensorflow.python.framework import ops


ops.reset_default_graph()


x_vals = np.array([1., 3., 5., 7., 9.])

x_data = tf.placeholder(tf.float32)

m_const = tf.constant(3.)

my_product = tf.multiply(x_data, m_const)


with tf.Session() as sess:

    print('m_const.eval() =>{} \n'.format(m_const.eval()))

    for x_val in x_vals:

        x_data_1 = sess.run(x_data, feed_dict={x_data:x_val})

        print('x_data_1 => {}'.format(x_data_1))


        my_product_1 = sess.run(my_product, feed_dict={x_data:x_val})

        print('my_product_1 => {}'.format(my_product_1))

        print('--------\n')


# m_const.eval() =>3.0 

# -------------------

# x_data_1 => 1.0

# my_product_1 => 3.0

# -------------------


# x_data_1 => 3.0

# my_product_1 => 9.0

# -------------------


# x_data_1 => 5.0

# my_product_1 => 15.0

# -------------------


# x_data_1 => 7.0

# my_product_1 => 21.0

# -------------------


# x_data_1 => 9.0

# my_product_1 => 27.0

# -------------------



Layering Nested Operations을 알아보겠습니다.

연산이 서로 이어지는 방식을 알아보기 위해 opeation graph에 multiple operation을 구성하겠습니다.

placeholder에 두 matrix를 곱한 후 덧셈을 하는 경우를 예로 들어보겠습니다.

def prinft(classtf):

    init = tf.global_variables_initializer()

    with tf.Session() as sess:

        init.run()

        print(classtf.eval())


ops.reset_default_graph()


# Create data to feed in

my_array = np.array([[1., 3., 5., 7., 9.],

                   [-2., 0., 2., 4., 6.],

                   [-6., -3., 0., 3., 6.]])


# Duplicate the array for having two inputs

x_vals = np.array([my_array, my_array + 1])

print(x_vals)

# array([[[ 1.,  3.,  5.,  7.,  9.],

#         [-2.,  0.,  2.,  4.,  6.],

#         [-6., -3.,  0.,  3.,  6.]],


#        [[ 2.,  4.,  6.,  8., 10.],

#         [-1.,  1.,  3.,  5.,  7.],

#         [-5., -2.,  1.,  4.,  7.]]])


# Declare the placeholder

x_data = tf.placeholder(tf.float32, shape=(3, 5))


# Declare constants for operations

m1 = tf.constant([[1.],[0.],[-1.],[2.],[4.]])

printf(m1)

# [[ 1.]

#  [ 0.]

#  [-1.]

#  [ 2.]

#  [ 4.]]


m2 = tf.constant([[2.]])

printf(m2)

# [[2.]]


a1 = tf.constant([[10.]])

printf(a1)

# [[10.]]


이제 matrix multiplication을 해보겠습니다.

A(3x5) * m1(5x1) = (3x1)이 만들어지고 나머지 연산은 상수곱과 덧셈이기 때문에 차원은 변하지 않습니다.

init = tf.global_variables_initializer()

with tf.Session() as sess:

    init.run()


    prod1 = tf.matmul(x_data, m1)

    prod2 = tf.matmul(prod1, m2)

    add1 = tf.add(prod2, a1)


    for x_val in x_vals:

        result = sess.run(add1, feed_dict={x_data: x_val})

        print('result => \n{}\n'.format(result))


# result => 

# [[102.]

#  [ 66.]

#  [ 58.]]


# result => 

# [[114.]

#  [ 78.]

#  [ 70.]]        




참고 자료: 

[1]TensorFlow Machine Learning Cookbook, Nick McClure

[2]https://github.com/nfmcclure/tensorflow_cookbook

#!/usr/bin/env python3


Activation  Function


activation function는 신경망의 필수 요소이기 때문에 신경망을 사용할 때는 활성화 함수를 자주 접하게 됩니다.

activation function의 목표는 가중치와 편향치를 조절하는 것이며 텐서플로에서 activation function는 텐서에 적용되는 비선형 연산입니다.


신경망에 비선형성을 도입하는 가장 일반적인 방법은 ReLU 함수가 있습니다.

import tensorflow as tf

import numpy as np

import matplotlib.pyplot as plt


def printf(tfclass):

    init = tf.global_variables_initializer()

    with tf.Session() as sess:

        init.run()

        print(tfclass.eval())


line = tf.linspace(-10., 10., num=100)

def plot_act_func(model):

    init = tf.global_variables_initializer()

    with tf.Session() as sess:

        init.run()

        x = line.eval()

        y = model.eval()

    plt.plot(x, y)

    plt.show()


relu_rlt = tf.nn.relu([-3., 3., 10.])

printf(relu_rlt)

# [ 0.  3. 10.]


relu = tf.nn.relu(line)

plot_act_func(relu)

ReLU Function



ReLU activation function의 선형 증가량에 상한을 설정하고 싶을 때가 있습니다.

max(0, x) 함수를 min()함수로 감싸서 구현할 수 있습니다. 텐서플로에는 ReLU6가 구현되어 있고

Relu6 = min(max(0, x), 6)으로 정의되어 있습니다.


ReLU6 이 함수는 매끄럽지 않은 각진 모양의 sigmoid 함수로 생각할 수 있습니다.

relu6_rlt = tf.nn.relu6([-3., 3., 10.])

printf(relu6_rlt)

# [0. 3. 6.]


relu6 = tf.nn.relu6(line)

plot_act_func(relu6)

relu6 function



sigmoid 함수는 연속이고 매끄러운 가장 일반적인 activation function입니다. 로지스틱 함수라고도 하며, 수식으로는

1 / (1+exp(-x))로 표현합니다. sigmoid 함수는 학습 과정에서 역전파 항을 0으로 만들어 버리는 경향이 있기 때문에 자주 사용하지는 않습니다.


sig_result = tf.nn.sigmoid([-1., 0., 1.])

printf(sig_result)

# [0.26894143 0.5        0.7310586 ]


sigmoid = tf.nn.sigmoid(line)

plot_act_func(sigmoid)

sigmoid function



또 다른 activation function하이퍼볼릭 탄젠트 함수가 있습니다. 하이퍼볼릭 탄젠트 함수는 sigmoid 함수와 아주 비슷하지만, 함수 값의 범위가 -1에서 1입니다.

tanh_rlt = tf.nn.tanh([-1.0, 0., 1.])

printf(tanh_rlt)

# [-0.7615942  0.         0.7615942]


tanh = tf.nn.tanh(line)

plot_act_func(tanh)

tanh function



softsign 함수도 activation function로 사용할 수 있습니다.

x / (abs(x) + 1)로 표현할 수 있으며 부호sign 함수를 연속 함수로 근사한 것입니다.

sosign = tf.nn.softsign([-1., 0., -1.])

printf(sosign)

# [-0.5  0.  -0.5]


softsign = tf.nn.softsign(line)

plot_act_func(softsign)

softsign function



softplus 함수는 매끄럽게 만든 ReLU 함수라고 할 수 있다. 이 함수의 식은 log(exp(x) + 1)

softplus_rlt = tf.nn.softplus([-1., 0., -1.])

printf(softplus_rlt)

# [0.31326166 0.6931472  0.31326166]


softplus = tf.nn.softplus(line)

plot_act_func(softplus)

softplus function

입력값이 커지면 softplus 함수값은 무한대로 가고, softsign 함수 값은 1에 수렴합니다.

반대로 입력 값이 작아지면 softplus 함수 값은 0에 수렴하고, softsign함수값은 -1에 수렴합니다.



지수 선형 유닛(ELU, Exponential Linear Unit) 함수는 softplus 함수와 비슷하지만 하부 점근선이 -1입니다.

x<0일 때는 exp(x)+1이고, 그외에는 x입니다.

elu_rlt = tf.nn.elu([-1.0, 0., -1.])

printf(elu_rlt)

# [-0.63212055  0.         -0.63212055]


elu = tf.nn.elu(line)

plot_act_func(elu)

elu function




참고 자료: 

[1]TensorFlow Machine Learning Cookbook, Nick McClure

'Tensorflow > Introduction' 카테고리의 다른 글

placeholder, marix, operation  (0) 2018.04.25
Getting Start Tensorflow  (0) 2018.04.25

#!/usr/bin/env python3


placeholder, marix, operation


변수는 텐서를 입력받아 변수를 출력하는 Variable()함수를 이용하여 주로 생성합니다.

이 함수는 변수 선언만 하기 때문에 변수 초기화를 별도로 해줘야 합니다.

import tensorflow as tf


my_var = tf.Variable(tf.zeros([2, 3]), dtype=tf.float32, name='my_var')


init = tf.global_variables_initializer()

with tf.Session() as sess:

    sess.run(init)


    result = my_var.eval()

    print(result)

    # [[0. 0. 0.]

    # [0. 0. 0.]]



placeholder는 계산 그래프에 데이터가 투입되는 위치를 나타냅니다. 세션의 feed_dict 인자를 통해 placeholder 데이터를 투입합니다.

계산에 placeholder를 넣기 위해서는 placeholder에 대해 하나 이상의 연산을 수행해야 합니다.

import numpy as np


with tf.Session() as sess:

    x = tf.placeholder(tf.float32, shape=[2, 2])

    y = tf.identity(x) # Return a tensor with the same shape and contents as input.

    x_vals = np.random.rand(2, 2)


    print(sess.run(y, feed_dict={x: x_vals}))

    # [[0.18282834 0.35173032]

    #  [0.3008346  0.14677659]]



다음은 matrix를 다루는 몇가지 방법에 대해 알아보겠습니다.

sess =  tf.Session()

identity_matrix = tf.diag([1., 1., 1.]) # identity matrix

A = tf.truncated_normal([2, 3], mean=1, stddev=1, dtype=tf.float32)

B = tf.fill([2, 3], 5.)

C = tf.random_uniform([3, 2], dtype=tf.float32)


np_arr = np.array([[1, 2, 3],

                       [-3, -7, -1],

                       [0, 5, -2]])

D = tf.convert_to_tensor(np_arr, dtype=tf.float32)



print(sess.run(identity_matrix))

# [[1. 0. 0.]

#  [0. 1. 0.]

#  [0. 0. 1.]]


print(sess.run(A))

# [[0.25446475 1.108418   2.5896869 ]

#  [0.3214993  0.6533705  0.8581022 ]]


print(sess.run(B))

# [[5. 5. 5.]

#  [5. 5. 5.]]


print(sess.run(C))

# [[0.9613472  0.97370124]

#  [0.4405172  0.7275435 ]

#  [0.9694842  0.23063374]]


print(sess.run(D))

# [[ 1.  2.  3.]

#  [-3. -7. -1.]

#  [ 0.  5. -2.]]


# 더하기 빼기는 다음과 같이 사용합니다.

print(sess.run(A+B))

# [[6.5324025 6.2761655 7.3138623]

#  [5.8994517 7.0984983 6.506235 ]]


print(sess.run(A-B))

# [[-4.5335164 -4.079894  -2.3542004]

#  [-4.500795  -5.3273354 -2.5056663]]


# 행렬곱은 다음 함수를 사용합니다.

print(sess.run(tf.matmul(B, identity_matrix)))

# [[5. 5. 5.]

#  [5. 5. 5.]]


print(sess.run(tf.transpose(C)))

# [[0.16169488 0.08706641 0.3332044 ]

#  [0.18076909 0.5893874  0.8159915 ]]


print(sess.run(tf.matrix_determinant(D)))

# -38.0


print(sess.run(tf.matrix_inverse(D)))

# [[-0.50000006 -0.5        -0.50000006]

#  [ 0.15789475  0.05263158  0.21052633]

#  [ 0.39473686  0.13157895  0.0263158 ]]


print(sess.run(tf.cholesky(identity_matrix)))

# [[1. 0. 0.]

#  [0. 1. 0.]

#  [0. 0. 1.]]


eig_value, eig_vector = sess.run(tf.self_adjoint_eig(D))

print(eig_value)

# [-10.659076    -0.22750695   2.886583  ]


print(eig_vector)

# [[-0.21749546 -0.6325011  -0.74339646]

#  [-0.84526515 -0.25879988  0.46749276]

#  [ 0.48808062 -0.7300446   0.4783433 ]]



나눗셈과 외은 다음과 같이 구합니다.

with tf.Session() as sess:

    f = tf.div(3, 4) # 몫만 표현

    print (f.eval()) # 0


    f1 = tf.truediv(3, 4) # 나눗셈 결과를 소수로 표현

    print(f1.eval()) # 0.75


    f2 = tf.floordiv(3.0, 4.0) # 몫을 소수로 표현

    print(f2.eval()) # 0.0


    f3 = tf.mod(22.0, 5.0) # 나머지

    print(f3.eval()) # 2.0


    f4 = tf.cross([1., 0., 0.], [0., 1., 0.]) # 외적

    print(f4.eval()) # [0. 0. 1.]



tan(pi/4)는 다음과 같이 구할 수 있습니다.

init = tf.global_variables_initializer()

with tf.Session() as sess:

init.run()

result = tf.div(tf.sin(np.pi/4.), tf.cos(np.pi/4.))

print(result)

# 1.0



다항함수 3*x^2 -x + 10의 결과는 다음 코드로 구현할 수 있습니다.

def custom_polynomial(val):

    return(3*tf.square(val) - val + 10)


init = tf.global_variables_initializer()

with tf.Session() as sess:

init.run()

result = custom_polynomial(11).eval()

print(result)

# 362




참고 자료: 

[1]TensorFlow Machine Learning Cookbook, Nick McClure

'Tensorflow > Introduction' 카테고리의 다른 글

Activation Function  (0) 2018.04.25
Getting Start Tensorflow  (0) 2018.04.25

#!/usr/bin/env python3


Getting Start Tensorflow


tensorflow는 객체로 만들어지기 때문에 출력을 위해 printf를 정의하고 이 것을 사용하겠습니다.

import tensorflow as tf


def printf(tfclass):

    init = tf.global_variables_initializer()

    with tf.Session() as sess:

        sess.run(init)

        rlt = tfclass.eval()

    print(rlt)

    

0 값으로 채워진 텐서는 다음과 같이 생성합니다.

zero_tsr = tf.zeros([3, 2])

printf(zero_tsr)

# [[0. 0.]

#  [0. 0.]

#  [0. 0.]]


1 값으로 채워진 텐서는 다음과 같이 생성합니다.

ones_tsr = tf.ones([3, 2])

printf(ones_tsr)

# [[1. 1.]

#  [1. 1.]

#  [1. 1.]]


동일한 상수값으로 채워진 텐서는 다음과 같이 생성합니다.

filled_tsr = tf.fill([3, 2], 9)

printf(filled_tsr)

# [[9 9]

#  [9 9]

#  [9 9]]


기존 상수를 이용해 텐서를 생성할 때는 다음 방식을 사용합니다.

constant_tsr = tf.constant([1, 2, 3])

printf(constant_tsr)

# [1 2 3]


기존 텐서의 형태를 바탕으로 텐서 변수를 초기화하는 것도 가능합니다.

zeros_similar = tf.zeros_like(constant_tsr)

printf(zeros_similar)

# [0 0 0]

ones_similar = tf.ones_like(constant_tsr)

printf(ones_similar)

# [1 1 1]


텐서플로는 구간을 지정하는 방식으로 텐서를 선언할 수 있습니다. 다음 함수는 range()나 numpy의 linspace()와 비슷하게 동작합니다.

linear_tsr = tf.linspace(0.0, 1.0, num=3)

printf(linear_tsr)

# [0.  0.5 1. ]


integer_seq_tsr = tf.range(6.0, 15, delta=3)

printf(integer_seq_tsr)

# [ 6.  9. 12.]


랜덤한 숫자도 뽑아낼 수 있습니다.

randunif_tsr = tf.random_uniform([3, 2], minval=0, maxval=1, dtype=tf.float32)

printf(randunif_tsr)

# [[0.218009   0.7311672 ]

#  [0.6954018  0.2027992 ]

#  [0.95226717 0.9950316 ]]


randnorm_tsr = tf.random_normal([3, 2], mean=0.0, stddev=1.0)

printf(randnorm_tsr)

# [[-0.45060402 -1.6076114 ]

#  [ 0.7157349  -0.28653365]

#  [ 1.2830635   0.6957943 ]]


특정 범위에 속하는 정규 분포 임의의 값을 생성하고 싶은 경우에 지정한 평균에서 항상 표준편차 2배 이내의 값을 뽑아줍니다.

truncnorm_tsr = tf.truncated_normal([3, 2], mean=3.0, stddev=1.0)

printf(truncnorm_tsr)

# [[2.6660793 2.3485358]

#  [3.378799  2.757817 ]

#  [2.8825157 1.9243042]]


배열의 항목을 임의로 섞을 때

shuffle_output = tf.random_shuffle(truncnorm_tsr)

printf(shuffle_output)

# [[2.174755  4.001117 ]

#  [2.6528723 2.8258555]

#  [3.5614102 2.8608997]]


cropped_output = tf.random_crop(shuffle_output, [3, 2])

printf(cropped_output)

# [[2.6678126 2.087521 ]

#  [1.5311174 4.574707 ]

#  [2.400455  3.175764 ]]




참고 자료: 

[1]TensorFlow Machine Learning Cookbook, Nick McClure

'Tensorflow > Introduction' 카테고리의 다른 글

Activation Function  (0) 2018.04.25
placeholder, marix, operation  (0) 2018.04.25

#!/usr/bin/env python3


Grid Search에 pipeline 적용


Grid Search에 pipeline을 사용하는 방식

parameter를 정의하고, 이 parameter 그리드와 pipeline으로 GridSearchCV의 객체를 만듭니다.

객체를 만들 때는 각 parameter가 pipeline의 어떤 단계에 속한 것인지 알려줘야 합니다.

C와 gamma parameter는 두 번째 단계인 SVC의 parameter입니다. 만약 이 단계의 이름이 'svc'라면 pipeline용 parameter 그리드는 단계 이름과 parameter 이름을 '__'로 연결합니다.

그래서 SVC의 parameter C를 Grid Search로 탐색하려면 parameter Grid dictionary의 키를 'svc__C'로 해야합니다.

import numpy as np

from sklearn.pipeline import Pipeline

from sklearn.datasets import load_breast_cancer

from sklearn.model_selection import train_test_split, GridSearchCV

from sklearn.preprocessing import MinMaxScaler

from sklearn.svm import SVC


cancer = load_breast_cancer()

x_train, x_test, y_train, y_test = train_test_split(cancer.data, cancer.target,

                                                    stratify=cancer.target, random_state=0)


scaler_tuple = ('scaler', MinMaxScaler())

model_tuple = ('svc', SVC())


pipe = Pipeline([scaler_tuple, model_tuple])

pipe.fit(x_train, y_train)


values = np.array([0.001, 0.01, 0.1, 1, 10, 100])

params = {'svc__C':values, 'svc__gamma':values}


grid = GridSearchCV(pipe, param_grid=params, cv=5)

grid.fit(x_train, y_train)


print('optimal train score: {:.3f}'.format(grid.best_score_))

# optimal train score: 0.984


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

# test score: 0.951


print('optimal parameter: {}'.format(grid.best_params_))

# optimal parameter: {'svc__C': 10.0, 'svc__gamma': 0.1}



이전 포스팅 참조하기

Grid Search: [1]pipeline


이전 포스팅에서 본 그리드 서치와 다른 점은 교차 검증의 각 분할에 MinMaxScaler가 훈련 폴드에 매번 적용되어, 매개변수 검색 과정에서 검증 폴더의 정보가 누설되지 않은 것입니다.

import matplotlib.pyplot as plt

from mglearn.plots import plot_proper_processing


plot_proper_processing()

plt.show()

교차 검증 반복 안에서 전처리가 될 때 데이터 사용 형태




교차 검증에서 정보 누설에 의한 영향은 전처리 종류에 따라 다릅니다. 검증 폴드를 사용해 데이터의 스케일을 조정하는 경우엔 심각한 문제가 생기지 않지만, 검증 폴드를 이용해 특성을 추출하거나 선택하면 결과가 확연히 달라집니다. 다음 코드로 이 것을 확인할 수 있습니다.

rnd = np.random.RandomState(seed=0)

x = rnd.normal(size=(100, 10000))

y = rnd.normal(size=(100,))


데이터셋을 무작위로 생성해서 데이터x와 타깃 y사이에는 아무런 관계가 없습니다(즉 독립입니다.) 그러므로 이 데이터셋으로 무언가를 학습하기는 불가능합니다. SelectPercentile로 10,000개 중 가장 유용한 특성을 선택하고 교차 검증을 사용하여 Ridge회귀를 평가 하겠습니다.

from sklearn.feature_selection import SelectPercentile, f_regression


select = SelectPercentile(score_func=f_regression, percentile=5)

select.fit(x, y)


x_selected = select.transform(x)

print('{}'.format(x_selected.shape))

# (100, 500)


from sklearn.model_selection import cross_val_score

from sklearn.linear_model import Ridge


cv_score = cross_val_score(Ridge(), x_selected, y, cv=5)

print('ridge score: {:.3f}'.format(np.mean(cv_score)))

# ridge score: 0.915

교차 검증으로 계산한 평균 R-square는 91.5%로 매우 좋은 모델입니다. 데이터셋을 완전히 무작위로 만들었으니 있을 수 없는 일입니다. 교차 검증 밖에서 특성을 선택했기 때문에 훈련과 테스트 폴드 양쪽에 연관된 특성이 찾아 질 수 있습니다.

테스트 폴드에서 유출된 정보는 매우 중요한 역할을 하기 때문에 비현실적으로 높은 결과가 나왔습니다.



select_tuple = ('select', SelectPercentile(score_func=f_regression, percentile=5))

model_tuple = ('ridge', Ridge())


pipe = Pipeline([select_tuple, model_tuple])

cv_score_pipe = cross_val_score(pipe, x, y, cv=5)

print('ridge score(pipe): {:.3f}'.format(np.mean(cv_score_pipe)))

# ridge score(pipe): -0.086

이번에는 R-square가 음수라 성능이 매우 낮은 모델임을 나타냅니다. 파이프라인을 사용했기 때문에 특성 선택이 교차 검증 반복 안으로 들어갔습니다. 이 말은 훈련 폴드를 사용해서만 특성이 선택되었고 테스트 폴드는 사용하지 않았다는 뜻입니다. 특성 선택 단계에서 훈련 폴드의 타깃값과 연관된 특성을 찾았지만, 전체 테이터가 무작위로 만들어졌으니 테스트 폴드의 타깃과는 연관성이 없습니다. 이 예는 특성 선택 단계에서 일어나는 정보 누설을 막는 것이 모델의 성능을 평가하는데 큰 차이를 만든다는 것을 보여줍니다.




참고 자료: 

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

'algorithm chain & pipeline > pipeline' 카테고리의 다른 글

pipeline  (0) 2018.04.20

#!/usr/bin/env python3


pipeline


입력 데이터의 표현 형태에 매우 민감한 머신러닝 algorithm이 많습니다.

직접 데이터의 스케일을 조정하고 특성을 연결하거나, 비지도 학습으로 특성을 만들기도 합니다.

따라서 대부분의 머신러닝은 하나의 algorithm으로 이뤄져 있지 않고, 여러 단계의 처리 과정과 머신러닝 모델이 연결되어 있습니다.


다음은 데이터를 분할하고 최솟값, 최댓값을 찾아 데이터의 스케일을 바꾸고 SVM훈련시키는 코드입니다.

SVC는 이전 포스팅을 참고하세요

[1]Kernelized Support Vector Machines


from sklearn.svm import SVC

from sklearn.datasets import load_breast_cancer

from sklearn.model_selection import train_test_split

from sklearn.preprocessing import MinMaxScaler


cancer = load_breast_cancer()

print('{}'.format(cancer.keys()))

# dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])


x_train, x_test, y_train, y_test = train_test_split(cancer.data, cancer.target,

                                                    stratify=cancer.target, random_state=0)


scaler = MinMaxScaler()

scaler.fit(x_train)


x_train_scaled = scaler.transform(x_train)

x_test_scaled = scaler.transform(x_test)


svc = SVC(C=1, kernel='rbf', gamma='auto', degree=3)

svc.fit(x_train_scaled, y_train)


pre_train_score = svc.score(x_train_scaled, y_train)

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

# 0.955


pre_test_score = svc.score(x_test_scaled, y_test)

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

# 0.951



단순한 GridSearchCV를 사용해서 더 좋은 SVC parameter를 찾는 방법은 다음과 같습니다.

from sklearn.model_selection import GridSearchCV

import numpy as np


values = np.array([0.001, 0.01, 0.1, 1, 10, 100])

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


grid = GridSearchCV(SVC(), param_grid=params, cv=5)

grid.fit(x_train_scaled, y_train)


print('optimal parameter {}'.format(grid.best_params_))

# optimal parameter {'C': 1.0, 'gamma': 1.0}


print('best CV score {:.3f}'.format(grid.best_score_))

# best CV score 0.981


print('best test score {:.3f}'.format(grid.score(x_test_scaled, y_test)))

# best test score 0.944

여기서 스케일을 조정한 데이터를 사용해서 SVC의 parameter에 대해 grid search를 수행했습니다.

데이터의 최솟값과 최댓값을 계산할 때 학습을 위해 train set에 있는 모든 데이터를 사용했습니다. 후에 스케일이 조정된 train data에서 교차 검증을 사용해 grid search를 수행했습니다. 교차 검증의 각 분할에서 원본 훈련 세트 데이터의 어떤 부분은 훈련 폴드가 되고 어떤 부분은 검증 폴드가 됩니다. 검증 폴드는 훈련 폴드로 학습된 모델이 새로운 데이터에 적용될 때의 성능을 측정하는 데 사용합니다. 그러나 데이터 스케일을 조정할 때 검증 폴드에 있는 정보까지 이미 사용했습니다. 다시 말하면 교차 검증의 반복마다 선택된 검증 폴드는 전체 훈련 세트의 일부이며, 우리나는 데이터의 스케일을 조정하기 위해 전체 훈련 세트를 이용했습니다. 하지만 이는 새로운 데이터가 모델에 나타날 때와는 완전히 다릅니다. 새로운 데이터가 관측되면 이 데이터는 훈련 데이터의 스케일 조정에 사용되지 않은 것이라, 그 최솟값과 최댓값이 훈련 데이터와 다를 수 있습니다.


다음 코드는 이 과정을 시각화하여 보여줍니다.

from mglearn.plots import plot_improper_processing

import matplotlib.pyplot as plt


plot_improper_processing()

plt.show()

교차 검증 반복 밖에서 전처리가 될 때 데이터 사용 형태

이렇기 때문에 교차 검증의 분할 방식은 모델이 새 데이터를 만났을 때를 올바로 반영하지 못하고 있습니다. 검증 폴드 데이터의 정보가 모델 구축 과정에 이미 누설되었으므로 교차 검증에서 최적의 매개변수를 찾지 못하고 낙관적인 결과가 만들어지게 됩니다.


이 문제를 해결하려면 교차 검증의 분할이 모든 전처리 과정보다 앞서 이뤄저야 합니다. 데이터셋의 정보를 이용하는 모든 처리 과정은 데이터셋의 훈련 부분에만 적용되어야 하므로 교차 검증 반복 안에 있어야 합니다.


scikit-learn에서 cross_var_score 함수와 GridSearchCV로 이런 방식을 구현하려면 Pipeline을 사용하면 됩니다.


Pipeline은 여러 처리 단계를 하나의 scikit-learn 추정기 형태로 묶어주는 파이썬 클래스입니다. Pipeline은 fit, predict, score 메소드를 제공합니다.


Pipeline을 사용하는 가장 일반적인 경우는 분류기 같은 지도 학습 모델과 전처리 단계를 연결할 때입니다.



MinMaxScaler로 데이터의 스케일을 조정하고 SVM 모델을 훈련시키는 workflow를 Pipeline을 사용해 표현해보겠습니다.

from sklearn.pipeline import Pipeline


scaler_tuple = ('scaler', MinMaxScaler())

model_tuple = ('svm', SVC())


pipe = Pipeline([scaler_tuple, model_tuple])

pipe.fit(x_train, y_train)


pipe.fit은 첫 번째 단계(scaler)의 fit 매소드를 호출하여 훈련데이터를 변환하고,

마지막에는 변환된 데이터에 SVM모델을 학습시킵니다. 테스트 세트로 평가하려면 pipe.score를 호출합니다.

pipe_train_score = pipe.score(x_train, y_train)

pipe_test_score = pipe.score(x_test, y_test)


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

# 0.955


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

# 0.951

이 값은 전처리한 후 훈련점수와 테스트 점수가 같습니다.



참고 자료: 

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

'algorithm chain & pipeline > pipeline' 카테고리의 다른 글

Grid Search에 pipeline 적용  (0) 2018.04.20

#!/usr/bin/env python3


불확실성 고려


confusion matrix와 classifier report는 예측 결과를 자세히 분석할 수 있도록 도와줍니다.

하지만 예측값은 model에 담긴 많은 정보가 이미 손실된 상태입니다.

대부분의 classifier는 확신을 가늠하기 위한 decision_function이나 predict_proba 메소드를 제공합니다.

예측을 만들어내는 것은 decision_function, predict_proba 출력의 critical value를 검증하는 것입니다.


binary search에서 decision_function은 0, predict_proba는 0.5를 critical value로 사용합니다.


다음 예는 음성 클래스 데이터 포인트 400개와 양성 클래스 데이터 포인트 50개로 이뤄진 불균형 데이터셋의 classifier report입니다.

from mglearn.plots import plot_decision_threshold

import matplotlib.pyplot as plt


plot_decision_threshold()

plt.show()

decision function의 heatmap과 critical value 변화에 따른 영향



classification_report 함수를 사용해서 두 클래스의 정밀도와 재현율을 평가해보겠습니다.

from mglearn.datasets import make_blobs

from sklearn.model_selection import train_test_split

from sklearn.svm import SVC

from sklearn.metrics import classification_report


x, y = make_blobs(n_samples=(400, 50), centers=2, cluster_std=[7, 2], random_state=22)

x_train, x_test, y_train, y_test = train_test_split(x, y, stratify=y, random_state=22)

svc = SVC(gamma=0.5) # degree=3, C=1, gamma='auto', kernel='rbf'

svc.fit(x_train, y_train)


rpt_result = classification_report(y_test, svc.predict(x_test))

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

#              precision    recall  f1-score   support


#           0       0.92      0.91      0.91       100

#           1       0.36      0.38      0.37        13


# avg / total       0.85      0.85      0.85       113

클래스 1에 대해 36%, 재현율은 38%입니다. class 0의 샘플이 매우 많으므로 classifier는 class 0에 초점을 맞추고 있습니다.


만약 class 1의 재현율을 높이는게 중요하다고 가정하면

class 1로 잘못분류된 FP(False Positive)보다 TP(True Positive)를늘려야 한다는 뜻입니다.

svc.predict로 만든 예측은 이 조건을 만족하지 못했지만 critical value를 조정하여 class 1의 재현율을 높이도록 예측을 조정할 수 있습니다.


기본적으로 decision_function의 값이 0보다 크면 class 1로 분류 됩니다. 더 많은 데이터 포인트가 class 1로 분류되려면 critical value를 낮춰야 합니다.

y_pred_lower_threshold = svc.decision_function(x_test) > -0.8

rpt_result_adj = classification_report(y_test, y_pred_lower_threshold)

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

#              precision    recall  f1-score   support


#           0       0.94      0.87      0.90       100

#           1       0.35      0.54      0.42        13


# avg / total       0.87      0.83      0.85       113

class 1의 정밀도는 낮아졌지만 재현율은 높아졌습니다.


간단한 예제를 위해 test set의 결과를 바탕으로 critical value를 선택했습니다.

실제로는 test set를 사용하면 안되며, 다른 parameter처럼 test set에서 decision critical value를 선택하면 과도하게 낙관적인 결과가 나옵니다. 대신에 검증세트나 교차 검증을 사용해야 합니다.



참고 자료: 

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

#!/usr/bin/env python3


Binary Classifier Evaluation


binary clssifier는 널리 사용되고 개념도 쉬운 머신러닝 알고리즘이지만 이렇게 간단한 작업을 평가하는 데에도 주의해야할 점이 많습니다.

정확도를 잘못 측정하는 경우에 대해 살펴보면

binary clssifier에는 양성 클래스와 음성 클래스가 있으며 양성 클래스관심 클래스 입니다.




1. Error Type

테스트가 양성이면 건강, 음성 이면 암진단으로 생각할 수 있습니다.

모델이 항상 완벽하게 작동하는 것은 아니니, 잘못 분류할 때가 있습니다.


건강한 사람을 음성으로 분류하면 추가 검사를 받게 할 것이며 이를 false positive거짓 양성이라 합니다.

반대로 암에 걸린사람을 음성으로 분류하여 제대로 된 검사나 치료를 받지 못하게 할 수도 있습니다. 이는 위의 오류보다 더 치명적으로 다가옵니다. 이런 종류의 잘못된 예측은 false negative거짓 음성이라 합니다.

통계학에서 false positive를 type-I Error false negative를 type-II Error라고 합니다.

암진단에서는 false negative가 false positive보다 중요도가 높습니다.




2. imbalanced dataset불균형 데이터셋

이 두 종류의 에러는 두 클래스 중 하나가 다른 것보다 훨씬 많을 때 더 중요합니다.

어떤 아이템이 사용자에게 보여진 impression노출 데이터로 클릭을 예측하는 것입니다.

아이템은 광고일 수도 있고, 관련 기사나 기타 등등 여러가지 일 수도 있습니다.

목표는 특정 상품을 보여주면 사용자가 클릭을 할지(관심 대상인지)를 예측하는 것입니다.


사용자가 관심 있는 것을 클릭할 때까지 100개의 광고나 글을 보여줘야 한다면

이 때 클릭이 아닌 데이터 99개클릭 데이터 1개가 데이터셋으로 만들어집니다.


즉 샘플의 99%가 클릭 아님(음성), 1%가 클릭(양성) 클래스에 속합니다.

이렇게 한 클래스가 다른 것보다 훨씬 많은 데이터셋을 imbalanced datasets불균형 데이터셋이라고 합니다.


클릭을 99% 정확도로 예측하는 분류기를 만들었다고 하면 정확도는 꽤 높아보이지만 불균형 클래스를 고려하지 못했습니다.


즉 머신러닝 모델을 만들지 않고서도 무조건 '클릭 아님'으로 예측하면 그 정확도는 99%입니다.

이 말은 모델이 '좋은 모델', '무조건 클릭 모델' 중에 하나일 수 있다는 사실입니다.

따라서 정확도로는 이 둘을 구분하기가 어렵습니다.


예를 위해서 digits 데이터셋을 사용해 숫자 9를 다른 숫자와 구분해서 9:1의 불균형한 데이터셋을 만들어보겠습니다.


from sklearn.datasets import load_digits

from sklearn.model_selection import train_test_split


digits = load_digits()

y = digits.target == 9


x_train, x_test, y_train, y_test = \

  train_test_split(digits.data, y, random_state=0)


# 항상 다수인 클래스(여기서는 '9 아님')를 예측값으로 내놓는 DummyClassifier를 사용해서 정확도를 계산해보면

from sklearn.dummy import DummyClassifier

import numpy as np


dummy_majority = DummyClassifier(strategy='most_frequent')

dummy_majority.fit(x_train, y_train)

pred_most_frequent = dummy_majority.predict(x_test)


print('예측된 유니크 레이블 ==> {}'.format(np.unique(pred_most_frequent)))

print('test score ==> {:.3f}'.format(dummy_majority.score(x_test, y_test)))

# 예측된 유니크 레이블 ==> [False]

# test score ==> 0.896


거의 아무것도 학습하지 않고 약 90% 정확도를 얻었습니다. 생각보다 높은 정확도를 가지고 있습니다.

하지만 문제에 따라서는 그저 무조건 한 클래스를 예측하기만 해도 될 수 있습니다.

실제 분류기 DecisionTreeClassifier를 사용한 것과 비교해보면

DecisionTreeClassifier는 이전 포스팅을 참고하세요

[1]Decision Tree -- intro, [2]Decision Tree, [3]Decision Tree Regressor

from sklearn.tree import DecisionTreeClassifier


tree = DecisionTreeClassifier(max_depth=2)

tree.fit(x_train, y_train)

pred_tree = tree.predict(x_test)


print('test score ==> {:.3f}'.format(tree.score(x_test, y_test)))

# test score ==> 0.918


정확도로만 보면 DecisionTreeClassifier가 더미 clssifier보다 조금 나을 뿐입니다.

비교를 위해 LogisticRegression과 기본 DummyClassifier clssifier 두 개를 더 살펴보겠습니다.


DummyClassifier는 무작위로 선택하므로 훈련 세트와 같은 비율의 예측값을 만듭니다.

DummyClassifier의 stategy의 기본값은 stratified로 클래스 레이블의 비율과 같은 비율로 예측 결과를 만들지만 타깃값 y_test와는 다르므로 정확도는 더 낮아집니다.

from sklearn.linear_model import LogisticRegression


dummy = DummyClassifier() # strategy='stratified'

dummy.fit(x_train, y_train)

pred_dummy = dummy.predict(x_test)


print('예측된 유니크 레이블 ==> {}'.format(np.unique(pred_dummy)))

print('dummy score ==> {:.3f}'.format(dummy.score(x_test, y_test)))

예측된 유니크 레이블 ==> [False  True]

# dummy score ==> 0.820

# logreg = LogisticRegression(C=0.1)


logreg.fit(x_train, y_train)

pred_logreg = logreg.predict(x_test)


print('예측된 유니크 레이블 ==> {}'.format(np.unique(pred_logreg)))

print('logreg score ==> {:.3f}'.format(logreg.score(x_test, y_test)))

# 예측된 유니크 레이블 ==> [False  True]

# logreg score ==> 0.978


무작위로 예측하는 DummyClassifier는 결과가 안 좋습니다. 반면 LogisticRegression 은 매우 좋으나 DummyClassifier도 81.3%를 맞추었으므로 실제로 이 결과가 유용한지 판단하기가 매우 어렵습니다.

imbalanced datasets에서 예측 성능을 정량화하는 데 정확도는 적절한 측정 방법이 아니기 때문입니다.

특히 pred_most_frequent와 pred_dummy처럼, 빈도나 무작위 기반 예측보다 얼마나 더 나은지 알려주는 평가지표가 필요합니다.

모델을 평가하는 지표라면 이런 비상식적인 예측은 피할 수 있어야 합니다.




3. confusion matrix오차행렬

confusion matix오차행렬은 binary clssifier 평가 결과를 나타낼 때 가장 많이 사용하는 방법입니다.

LogisticRegression의 예측 결과를 confusion_matrix 함수를 사용해서 확인해보겠습니다.

from sklearn.metrics import confusion_matrix


pred_logreg = logreg.predict(x_test)

confusion = confusion_matrix(y_test, pred_logreg)


print('confusion matrix \n{}'.format(confusion))

# confusion matrix 

# [[401   2]

# [  8  39]]


confusion_matrix의 출력은 2x2 배열입니다. 행은 정답 클래스에 해당하고, 열은 예측 클래스에 해당합니다.

각 항목의 숫자는 행에 해당하는 클래스(여기서는 '9 아님'과 '9')가 얼마나 많이 열에 해당하는 클래스로 분류되었는지를 나타냅니다.

다음은 confusion matrix를 시각적으로 보여주는 코드입니다.

import mglearn

import matplotlib.pyplot as plt

import matplotlib


matplotlib.rc('font', family='AppleGothic')

plt.rcParams['axes.unicode_minus'] = False


mglearn.plots.plot_confusion_matrix_illustration()

plt.show()

'nine'과 'not nine' 분류문제의 confusion matrix

>> confusion matrix의 대각선 성분은 정확히 분류된 경우고, 다른 항목은 한 클래스의 샘플들이 다른 클래스로 잘못 분류된 경우가 얼마나 많은지를 보여줍니다.



숫자 9를 양성 클래스로 정의하면 confusion matrix의 항목을 앞서 이야기한 false positive와 false negative로 연결할 수 있습니다.


true positive, false positive, true negative, false negative로 분류하고 약자로

TP, FP, TN, FN이라고 하면

mglearn.plots.plot_binary_confusion_matrix()

plt.show()

binary classifier의 confustion matrix


이제 이 confusion matrix를 사용하여 앞서 만든 모델들

1. DummyClassifier 2개와

2. DecisionTreeClassifier

3. LogisticRegression을 비교해보겠습니다.

pred_most_frequent = dummy_majority.predict(x_test)

pred_dummy = dummy.predict(x_test)

pred_tree = tree.predict(x_test)

pred_logreg = logreg.predict(x_test)


print('dummy model based on frequency')

print(confusion_matrix(y_test, pred_most_frequent))

print('\nrandom dummy model')

print(confusion_matrix(y_test, pred_dummy))

print('\ndecision tree')

print(confusion_matrix(y_test, pred_tree))

print('\nlogistic regression')

print(confusion_matrix(y_test, pred_logreg))


# dummy model based on frequency

# [[403   0]

#  [ 47   0]]


# random dummy model

# [[365  38]

#  [ 40   7]]


# decision tree

# [[390  13]

#  [ 24  23]]


# logistic regression

# [[401   2]

#  [  8  39]]


confusion_matrix를 보면 pred_most_frequent에서 잘못된 것이 보입니다.

항상 동일한 클래스를 예측하기 때문입니다.

반면에 pred_dummy는 특히 FN과 FP보다 TP가 매우 적고, TP보다 FP가 매우 많습니다.

pred_logreg는 거의 모든 면에서pred_tree보다 낫습니다.


이 행렬의 모든 면을 살펴보면 많은 정보를 얻을 수 있지만, 매우 수동적이며 정성적인 방법입니다.

'모델 평가와 성능 향상 > 평가 지표와 측정' 카테고리의 다른 글

불확실성 고려  (0) 2018.04.20

#!/usr/bin/env python3


nested cross-validation


GridSearchCV를 사용할 때 데이터를 train set와 test set로 한 번만 나누기 때문에, 결과가 불안정하고 테스트 데이터의 분할에 크게 의존합니다. 

이런 문제를 해결하기 위해 cross-validation 방식을 사용할 수 있습니다.

이를 nested cross-validation중첩교차검증이라 합니다.


nested cross-validation에서는 바깥쪽 루프에서 데이터를 train set와 test set로 나눈 여러개의 fold폴드를 만듭니다. 각 fold의 train set에 대해 grid search를 실행하며, 이 때 바깥쪽 루프에서 분할된 fold의 train set마다 optimal parameter가 다를 수 있습니다.

그런 다음 바깥쪽에서 분할된 fold의 test set의 점수를 optimal parameter 설정을 사용해 각각 측정합니다.


이 방법은 모델이나 parameter 설정이 아닌 테스트 점수의 목록을 만들어주고, grid search를 통해 찾은 optimal parameter가 모델을 얼마나 잘 일반화시키는지 알려줍니다.


새로운 데이터에 적용할 모델을 만드는 것이 아니니, nested cross-validation은 미래의 데이터에 적용하기 위한 예측 모델을 찾는데는 거의 사용하지 않습니다. 그러나 특정 데이터셋에서 주어진 모델이 얼마나 잘 일반화되는지 평가하는데 유용한 방법입니다.


GridSearchCV의 객체를 모델로 삼아 cross_val_score 함수를 호출하면 됩니다.

# library import

from sklearn.datasets import load_wine

from sklearn.model_selection import GridSearchCV, cross_val_score

from sklearn.svm import SVC


# datasets

wine = load_wine()


# create object

values = [0.001, 0.01, 0.1, 1, 10, 100]

param_grid = {'C':values, 'gamma':values}


svc= SVC()


# grid search

grid_search = GridSearchCV(svc, param_grid, cv=5)



scores = cross_val_score(grid_search, wine.data, wine.target, cv=5)


print('교차 검증 점수 ==> {}'.format(scores))

print('교차 검증 평균 점수 ==> {:.3f}'.format(scores.mean()))

# 교차 검증 점수 ==> [0.75675676 0.66666667 0.75       0.8        0.88235294]

# 교차 검증 평균 점수 ==> 0.771


>> SVC는 wine 데이터셋에서 평균 교차 정확도가 77.1%라고 말할 수 있습니다.


여기에서 안쪽 루프와 바깥쪽 루프에 각각 stratified 5 cross-validation을 사용했고

param_grid의 매개변수 조합은 6x6 = 36이고 이 때 만들어지는 모델은 36 x 5 x 5 = 900이므로

중첩 교차 검증은 연산 비용이 매우 큽니다


여기에서 안쪽 루프와 바깥쪽 루프에 같은 교차 검증 분할기를 사용했으며, 꼭 같을 필요는 없습니다.

위의 한 줄의 코드는 다음과 같이 표현할 수 있습니다.


# library import

import numpy as np


def nested_cv(x, y, inner_cv, outer_cv, Classifier, parameter_grid):

    outer_scores = []

    for train_samples, test_samples in outer_cv.split(x, y):

        best_params = {}

        best_score = -np.inf


        for parameters in parameter_grid:

            cv_scores = []


            for inner_train, inner_test in inner_cv.split(

                    x[train_samples], y[train_samples]):

                clf = Classifier(**parameters) # **kwargs:

                clf.fit(x[inner_train], y[inner_train])


                score = clf.score(x[inner_test], y[inner_test])

                cv_scores.append(score)


            mean_score = np.mean(cv_scores)

            if mean_score > best_score:

                best_score = mean_score

                best_params = parameters


        clf = Classifier(**best_params)

        clf.fit(x[train_samples], y[train_samples])

        outer_scores.append(clf.score(x[test_samples], y[test_samples]))

    return np.array(outer_scores)


# library import

from sklearn.model_selection import ParameterGrid, StratifiedKFold


scores = nested_cv(wine.data, wine.target, StratifiedKFold(5), StratifiedKFold(5), SVC, ParameterGrid(param_grid))

print('교차 검증 점수 ==> {}'.format(scores))

# cross-validation score ==> [0.64864865 0.66666667 0.63888889 0.68571429 0.79411765]


'모델 평가와 성능 향상 > 그리드 서치' 카테고리의 다른 글

asymmetric parameter with grid search  (0) 2018.04.05
cross-validation result analysis  (2) 2018.04.05
parameter overfitting  (0) 2018.04.04
simple grid search  (1) 2018.04.03

#!/usr/bin/env python3


asymmetric parameter with grid search


이전 포스팅 참조하기

SVC: [1]Kernelized Support Vector Machines


예를들어 SVCkernel parameter를 가지고 있는데 어떤 kernel을 사용하는지에 따라 관련있는 parameter들이 결정됩니다.

kernel='linear'이면 C parameter만 사용하고

kernel='rbf'이면 C와 gamma를 모두 사용합니다.


이런 경우에 kernel, C, gamma parameter의 모든 조합을 조사하는 것은 낭비입니다.


1. apply asymmetric parameter

이런 조건부 parameter조합을 적용하려면 GridSearchCV에 전달한 param_grid를 딕셔너리의 리스트로 만들기만 하면 됩니다.

# load library

from sklearn.datasets import load_breast_cancer

from sklearn.model_selection import train_test_split, KFold, GridSearchCV

from sklearn.svm import SVC


# datasets

cancer = load_breast_cancer()


# data paritition

x_train, x_test, y_train, y_test =\

  train_test_split(cancer.data, cancer.target,

                   random_state=0, test_size=0.3, stratify=cancer.target)


# create class

svc = SVC()

kfold = KFold(n_splits=5, shuffle=True, random_state=0)


values = [0.001, 0.01, 0.1, 1, 10, 100]

param_grid = [{'kernel':['rbf'], 'C':values, 'gamma':values},

               {'kernel':['linear'], 'C':values}]


grid_search = GridSearchCV(svc, param_grid, cv=kfold)

grid_search.fit(x_train, y_train)


# results

print('optimal parameter ==> {}'.format(grid_search.best_params_))

print('optimal parameter의 점수 ==> {:.3f}'.format(grid_search.best_score_))

print('optimal parameter로 일반화 점수 ==> {:.3f}'.format(grid_search.score(x_test, y_test)))

# optimal parameter ==> {'C': 100, 'kernel': 'linear'}

# optimal parameter의 점수 ==> 0.970

# optimal parameter로 일반화 점수 ==> 0.924



2. cv_results_ 결과 살펴보기

다음으로 cv_results_ 속성을 살펴보기 위해 pandas의 DataFrame으로 csv를 만든 후 일부만 보겠습니다.

# library import

import pandas as pd


results = pd.DataFrame(grid_search.cv_results_)


# write csv

results.T.to_csv('grid_search.cv_results_.csv')

cv_results_의 일부

>> kernel이 'linear'일 때는 'C'값만 변한 것을 확인할 수 있습니다.



참고 자료: 

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


'모델 평가와 성능 향상 > 그리드 서치' 카테고리의 다른 글

nested cross-validation  (1) 2018.04.05
cross-validation result analysis  (2) 2018.04.05
parameter overfitting  (0) 2018.04.04
simple grid search  (1) 2018.04.03

#!/usr/bin/env python3


cross-validation result analysis


이전 포스팅에서 parameter overfitting을 다뤘습니다.

GridSearchCV를 활용하여 최적 매개변수를 찾고, 이를 이용하여 모델의 성능을 향상시켰습니다. 

이번 포스팅에서는 GridSearchCV의 결과를 분석해보겠습니다.


cross-validation의 결과를 시각화 하면 검색 대상 매개변수가 모델의 일반화에 영향을 얼마나 주는지 알 수가 있습니다.

grid search는 연상 비용이 매우 크므로 비교적 간격을 넓게 하여 적은 수의 grid로 시작하는 것이 좋습니다.

그 다음 cross-validation의 결과를 분석하여 검색을 확장해 나갈 수 있습니다.

grid search의 결과는 cv_results_에 담겨 있어 DataFrame형태로 변환해서 보는 것이 도움이 됩니다.



1. iris 데이터셋으로 분석

# load library

from sklearn.datasets import load_iris

from sklearn.model_selection import train_test_split, KFold, GridSearchCV

from sklearn.svm import SVC


# datasets

iris = load_iris()


# data partition

x_train, x_test, y_train, y_test =\

  train_test_split(iris.data, iris.target,

                   random_state=0, test_size=0.3)


# create object

svc = SVC()

kfold = KFold(n_splits=10, shuffle=True, random_state=0) # stratified cross-validation


# param_grid

values = [0.001, 0.01, 0.1, 1, 10, 100, 1000]

param_grid = {'C':values, 'gamma':values}


# GridSearch

grid_search = GridSearchCV(svc, param_grid, cv=kfold)

grid_search.fit(x_train, y_train)


# result

print('최적 매개변수 점수 ==> {:.3f}'.format(grid_search.best_score_))

print('최적 매개변수 ==> {}'.format(grid_search.best_params_))

print('최적 매개변수의 테스트 점수 ==> {:.3f}'.format(grid_search.score(x_test, y_test)))

# 최적 매개변수 점수 ==> 0.981

# 최적 매개변수 ==> {'C': 10, 'gamma': 0.1}

# 최적 매개변수의 테스트 점수 ==> 0.978



import pandas as pd

results = pd.DataFrame(grid_search.cv_results_)

print('results \n{}'.format(results.head()))

DataFrame으로 표현한 grid_search.cv_results_

>> results의 행 하나는 특정한 하나의 매개변수 설정에 대응하며 각 설정에 대해 cross-validation의 모든 분할의 평균값, 표준편차를 포함한 결과가 기록되어 있습니다.

검색 대상 parameter grid가 2개 이므로, heatmap으로 시각화하기에 좋습니다.




2. 검색 결과를 heatmap으로 시각화

heatmap으로 시각화 하려면 각 parameter를 축으로 하는 numpy 배열을 만들어야합니다. 

7개의 grid를 사용했으므로 cross-validation의 평균을 7x7형태로 차원을 바꿔야합니다.

# library import

import mglearn

import matplotlib

import matplotlib.pyplot as plt

from mpl_toolkits.axes_grid1 import make_axes_locatable # colorbar의 크기를 정하기 위한 축 library


# matplotlib 설정

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

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


# values = [0.001, 0.01, 0.1, 1, 10, 100, 1000]

# param_grid = {'C':values, 'gamma':values}


# 차원 변형

mean_score = results['mean_test_score'].reshape(7, 7) 


# 시각화

score_image = mglearn.tools.heatmap(mean_score, xlabel='gamma', xticklabels=param_grid['gamma'],

                      ylabel='C', yticklabels=param_grid['C'])


ax = plt.gca() # GetCurrentAxis

divider = make_axes_locatable(ax)

cax = divider.append_axes('right', size='5%', pad='5%')

plt.colorbar(score_image, cax=cax)

plt.show()


gamma와 C값에 따른 cross-validation 평균 점수의 heatmap


>> heatmap의 각 포인트는 특정 parameter 설정에 대한 cross-validation 실행에 대응됩니다. cross-validation의 정확도가 높을 수록 밝은색으로, 낮을 수록 어두운색으로 표현 됩니다. parameter에 따라서 다양한 색깔 포인트들이 존재하는 것은 그 만큼 모델이 parameter 설정에 민감하다는 것을 나타냅니다. 



3. parameter가 적절하게 선택되지 않은 예

parameter 설정에 민감하기 때문에 범위가 중요하며 검색 범위가 적절하게 선택되지 않은 예를 살펴보겠습니다.

# library import

import mglearn

import matplotlib

import matplotlib.pyplot as plt

from mpl_toolkits.axes_grid1 import make_axes_locatable # colorbar 조정하기 위한 그래프 축 library

import numpy as np


# subplots

_, axes = plt.subplots(1, 3)


# param_grid

param_grid_linear = {'C':np.linspace(1, 2, num=6),

                                 'gamma': np.linspace(1, 2, num=6)}


param_grid_log = {'C':np.linspace(1, 2, num=6),

                             'gamma':np.logspace(-3, 2, num=6)}


param_grid_range = {'C':np.logspace(-3, 2, num=6),

                                'gamma':np.logspace(-7, -2, num=6)}


# visualization

param_grid_sets = [param_grid_linear, param_grid_log, param_grid_range]    

for p, ax in zip(param_grid_sets, axes.ravel()):

    svc = SVC()

    kfold = KFold(n_splits=10, shuffle=True, random_state=0) # [1]stratified cross-validation(교차검증)-- 이전 포스팅 참조 하세요


    grid_search = GridSearchCV(svc, param_grid=p, cv=kfold) # GridSearch(estimator, param_grid, cv) 

    grid_search.fit(x_train, y_train)

    mean_score = grid_search.cv_results_['mean_test_score'].reshape(6, 6)


    score_image = mglearn.tools.heatmap(mean_score, xlabel='gamma', xticklabels=p['gamma'],

                         ylabel='C', yticklabels=p['C'], ax=ax)


axis = plt.gca() # GetCurrentAxis

divider = make_axes_locatable(axis)

cax = divider.append_axes('right', size='5%', pad='5%')

plt.colorbar(score_image, ax=axes.tolist() ,cax=cax)

plt.show()


적절하지 않은 parameter grid의 heatmap


>>  [1] 첫 번째 그래프는 점수 변화가 전혀 없어서 전체 parameter grid가 거의 같은 색입니다. 이런 결과는 parameter의 스케일 범위가 부적절할 때 발생합니다.

그러나 parameter 설정이 바뀌어도 아무런 변화가 없다면, 그 parameter가 중요하지 않은 것일 수도 있습니다.

처음에는 극단적인 값을 적용하고, parameter를 바꿔가며 정확도를 살펴보는 것을 추천합니다.


[2] 두 번째 그래프는 세로 띠 형태입니다. 이 것은 C에 상관없이 gamma만 정확도에 영향을 준다는 것입니다.

gamma는 적절한 범위지만 C는 그렇지 못한 것이며, 혹은 중요하지 않은 것일 수도 있습니다.


[3] 세 번째 그래프는C와 gamma  둘 모두에 따라 값이 변했습니다. 하지만 그래프 왼쪽 아래 부분에서는 아무런 변화가 없습니다. 최적치가 그래프의 경계에 있으니 이 경계 너머에 더 좋은 값이 있다고 생각할 수 있고, 이 영역이 포함되도록 parameter 검색 범위를 바꿔줘야 함


cross-validation 점수를 토대로 parameter grid를 튜닝하는 것은 아주 안전한 방법이며, parameter들의 중요도를 확인하는데도 좋습니다. 그러나 최종 테스트 세트를 대상으로 여러 parameter 범위를 테스트해서는 안됩니다.


여태까지 대칭적 parameter grid만 탐색했지만(C가 6개면, gamma도 6개) 다음 포스트에서는 비대칭 매개변수 grid 탐색을 다뤄 보겠습니다.



참고 자료: 

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

'모델 평가와 성능 향상 > 그리드 서치' 카테고리의 다른 글

nested cross-validation  (1) 2018.04.05
asymmetric parameter with grid search  (0) 2018.04.05
parameter overfitting  (0) 2018.04.04
simple grid search  (1) 2018.04.03

#!/usr/bin/env python3


parameter overfitting


이전 포스팅에서 평가를 위해서는 모델을 만들 때 사용하지 않은 독립된 데이터셋이 필요하다고 했습니다.

독립된 데이터셋을 사용하는 방법에는 2가지가 있습니다.

첫 번째는 train_test_split을 2번 사용하여 데이터를 3등분하는 것이고

두 번째는 cross-validation을 사용하는 것입니다.


우선 첫 번째 방법부터 살펴보겠습니다. 이 방법은 아래 소스를 통해 그래프로 확인할 수 있습니다.

# library import

import mglearn

import matplotlib

import matplotlib.pyplot as plt


# matplotlib 설정

matplotlib.rc('font', family='AppleGothic'# 한글폰트

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


mglearn.plots.plot_threefold_split()

plt.show()

training set, validation set, test set의 3개의 폴드로 나눈 데이터



1. train_test_split을 이용한 iris데이터의 grid search

이번에는 iris 데이터로 살펴보겠습니다.

# load library

from sklearn.svm import SVC

from sklearn.model_selection import train_test_split

from sklearn.datasets import load_iris


# data load

iris = load_iris()


# train_test_split 1번

x_trainvalid, x_test, y_trainvalid, y_test=\

  train_test_split(iris.data, iris.target, random_state=0)


# train_test_split 2번

x_train, x_valid, y_train, y_valid =\

  train_test_split(x_trainval, y_trainval, random_state=1)  


print('x_train size:{}\nx_valid size:{}\nx_test size:{}'.format(x_train.shape, x_valid.shape, x_test.shape))

# x_train size:(84, 4)

# x_valid size:(28, 4)

# x_test size:(38, 4)


# grid search

values = [0.001, 0.01, 0.1, 1, 10, 100]

best_score = 0

for g in values:

    for c in values:

        svc = SVC(C=c, gamma=g).fit(x_train, y_train)

        scores = svc.score(x_valid, y_valid) # 검증세트로 svc를 평가


        if scores > best_score:

            best_score = scores

            best_param = {'C':c, 'gamma':g}

            

svc = SVC(**best_param).fit(x_trainvalid, y_trainvalid) # **kwargs: 딕셔너리 형태로 함수에 인자를 넘김

score_svc = svc.score(x_test, y_test)


print('최적 매개변수 점수 ==> {:.3f}'.format(best_score))

print('최적 매개변수 ==> {}'.format(best_param))

print('최적 매개변수에서 test ==> {:.3f}'.format(score_svc))

# 최적 매개변수 점수 ==> 0.964

# 최적 매개변수 ==> {'C': 10, 'gamma': 0.001}

# 최적 매개변수에서 test ==> 0.921


>> 최적 매개변수에서 최고점수는 96.4%이며 테스트 세트 점수는 92.1%입니다. 

새로운 데이터에 대해 92.1%만 정확하게 분류한다고 볼 수 있습니다.

테스트 세트로 둘 이상의 모델을 평가해서 그 중 더 나은 하나를 선택하는 것은 모델의 정확도를 매우 낙관적으로 추정하거나, 

overfitting이 생길 수 있으므로 주의해야합니다.


2. cross-validaion을 이용한 iris데이터의 grid search


일반화 성능을 더 잘 평가하려면 훈련 세트와 검증 세트를 한 번만 나누지 않고 

cross-validation을 사용해서 각 매개변수 조합의 성능을 평가할 수 있습니다.


cross-validation을 통해 어떤 매개변수가 선택되는지를 살펴보면

# library import

import mglearn

import matplotlib.pyplot as plt


mglearn.plots.plot_cross_val_selection()

plt.show()

cross-validation을 사용한 grid search의 결과


>> [0.001, 0.01, 0.1, 1, 10, 100]를 C와 gamma로 각각 설정한 후, cross-validation 에 한개씩, 모두 5개의 값을 계산합니다.

총 6x6x5 = 180개의 모델을 만들어서 모델 검정을 하기때문에 시간이 오래 걸립니다.


# library import

import numpy as np

from sklearn.svm import SVC

from sklearn.datasets import load_iris

from sklearn.model_selection import train_test_split


# datasets

iris = load_iris()


# data partition

x_train, x_test, y_train, y_test = \

  train_test_split(iris.data, iris.target,

                   random_state=0, test_size=0.3)


# grid search

values = [0.001, 0.01, 0.1, 1, 10, 100]

best_score = 0

for g in values:

    for c in values:

        svc = SVC(gamma=g, C=c).fit(x_train, y_train)

        kfold = KFold(n_splits=5, shuffle=True, random_state=0)

        scores = cross_val_score(svc, x_train, y_train, cv=kfold)

        score = np.mean(scores)


        if score > best_score:

            best_score = score

            best_param = {'gamma':g, 'C':c}


# 최적 매개변수로 모델을 다시 만듬             

svc = SVC(**best_param).fit(x_train, y_train)

print('최적 매개변수 점수 ==> {:.3f}'.format(best_score))

print('최적 매개변수 ==> {}'.format(best_param))

print('최적 매개변수에서 test ==> {:.3f}'.format(svc.score(x_test, y_test)))

# 최적 매개변수 점수 ==> 0.981

# 최적 매개변수 ==> {'gamma': 0.01, 'C': 100}

# 최적 매개변수에서 test ==> 0.978



cross-validation을 사용한 grid search를 매개변수 조정 방법으로 많이 사용하기 때문에

scikit-learn은 GridSearchCV를 제공합니다.


GridSearchCV는 딕셔너리 형태로 검색 대상 매개변수를 지정하며 필요한 모든 모델을 학습합니다. 아래 소스는 위의 소스와 같은 결과를 냅니다.

# library import

from sklearn.svm import SVC

from sklearn.datasets import load_iris

from sklearn.model_selection import train_test_split, GridSearchCV, KFold


# data load

iris = load_iris()


# data parition

x_train, x_test, y_train, y_test = \

  train_test_split(iris.data, iris.target,

                   random_state=0, test_size=0.3)


# create object

svc = SVC() # SVC모델 생성

kfold = KFold(n_splits=5, shuffle=True, random_state=0) # cross-validation 


values = [0.001, 0.01, 0.1, 1, 10, 100]

param_grid = {'gamma':values, 'C':values}  # GridSearchCV의 딕셔너리 생성


grid_search = GridSearchCV(svc, param_grid, cv=kfold)

grid_search.fit(x_train, y_train)


score = grid_search.score(x_test, y_test)

print('GridSearchCV를 이용한 최적 매개변수 점수 ==> {:.3f}'.format(grid_search.best_score_))

print('GridSearchCV를 이용한 최적 매개변수 ==> {}'.format(grid_search.best_params_))

print('GridSearchCV를 이용한 test점수 ==> {:.3f}'.format(score))

print('GridSearchCV를 이용한 최고 성능 모델 ==> \n{}'.format(grid_search.best_estimator_))

# GridSearchCV를 이용한 최적 매개변수 점수 ==> 0.981

# GridSearchCV를 이용한 최적 매개변수 ==> {'C': 10, 'gamma': 0.1}

# GridSearchCV를 이용한 test점수 ==> 0.978

# GridSearchCV를 이용한 최고 성능 모델 ==> 

#SVC(C=10, cache_size=200, class_weight=None, coef0=0.0, decision_function_shape='ovr', degree=3, gamma=0.1, kernel='rbf', max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False)


>> 이 소스는 더 간결해졌지만 많은 내용을 함축하고 있습니다.

다음에는 GridSearchCV를 통해 cross-validation 결과를 시각화 해보겠습니다.



참고 자료: 

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

'모델 평가와 성능 향상 > 그리드 서치' 카테고리의 다른 글

nested cross-validation  (1) 2018.04.05
asymmetric parameter with grid search  (0) 2018.04.05
cross-validation result analysis  (2) 2018.04.05
simple grid search  (1) 2018.04.03

+ Recent posts