#!/usr/bin/env python3


LASSO and Ridge Regression


이전 포스팅 보기

[1]Ridge, [2]Lasso


LASSO Ridge는 모두 출력 값에 미치는 regularization을 적용합니다.

tensorflow에서는 기울기A값에 의존하는 항을 cost function에 추가하면 이런 효과를 얻을 수 있습니다.


LASSO의 경우 기울기A가 특정 값 이상이 되면 cost를 크게 증가시키는 항을 추가해야합니다.

tensorflow의 논리 연산을 사용할 수도 있지만, 이렇게 하면 경사도를 계산할 수 없습니다. 대신에 step function을 연속 함수로 근사한 continuous heavyside step 함수를 조절해서 사용하여 문제를 해결 할 수 있습니다.


step function은 step이 중요합니다. step이 너무 높으면 수렴하지 않는 경우가 발생할 수 있습니다.


iris데이터셋으로 LASSO를 적용해보겠습니다. 


먼저 data를 로딩하고 placeholder를 생성하겠습니다.

import tensorflow as tf

from tensorflow.python.framework import ops

import numpy as np

from sklearn.datasets import load_iris


ops.reset_default_graph()


iris = load_iris()

# iris.keys(): dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])

# iris.feature_names: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']


regression_type = 'LASSO' # LASSO, Ridge


x_vals = iris.data[:, 3] # petal width

y_vals = iris.data[:, 0] # sepal length


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]))


연속함수로 근사한 LASSO의 cost function인 heavyside step function은 다음과 같이 쓸 수 있습니다.$$y = \frac {1}{e^{ \left( x-\theta \right) \cdot (-\delta) }+1}$$


Ridge의 cost function은 다음과 같습니다.

$$mean\left(\sum { \left( y-\overset { \wedge  }{ y }  \right) ^{ 2 } }\right) + mean \left(\theta \sum {A^{ 2 } } \right)$$

여기서 $\theta$는 critical value임계값을 말하며 $\delta$는 step의 sensitivity민감도를 나타냅니다.


activate function인 continuous heavyside step함수는 다음 코드로 시각화 할 수 있습니다.

deltas = [0.1, 1, 5, 50]

_, axes = plt.subplots(2, 2)


for ax, delta in zip(axes.ravel(), deltas):

    line = np.linspace(-5, 5)

    theta = 0.9

    step = 1

    y = 1/(np.exp((line-theta)*(-delta)) + 1) * step

    ax.plot(line, y)

    ax.set_title('$\delta$={}'.format(delta))

plt.show()

$\delta$값에 따른 heavyside step function



따라서 LASSO와 Ridge의 cost function을 고려한 연산과정은 다음과 같습니다

with tf.Session() as sess:

    fomula = tf.add(tf.matmul(x_data, A), b)


    if regression_type == 'LASSO':

        lasso_params = tf.constant(0.9, dtype=tf.float32) # limit slope

        heavyside_step = tf.truediv(1., tf.add(tf.exp(tf.multiply(tf.subtract(A, lasso_params), -50)), 1))

        regularization = tf.multiply(99., heavyside_step)

        loss = tf.add(tf.reduce_mean(tf.square(y_target-fomula)), regularization)


    elif regression_type == 'Ridge':

        ridge_params = tf.constant(1., dtype=tf.float32)

        ridge_loss = tf.reduce_mean(tf.square(A))


loss = tf.expand_dims(tf.add(tf.reduce_mean(tf.square(y_target-fomula)),

                                     tf.multiply(ridge_params, ridge_loss)), 0) 


    opt = tf.train.GradientDescentOptimizer(learning_rate=0.001)

    train_step = opt.minimize(loss)


    init = tf.global_variables_initializer()

    init.run()


    loss_vec = []

    for i in range(1500):

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

        rnd_x = x_vals[rnd_idx].reshape(-1, 1)

        rnd_y = y_vals[rnd_idx].reshape(-1, 1)


        my_dict = {x_data:rnd_x, y_target:rnd_y}

        sess.run(train_step, feed_dict=my_dict)

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

        loss_vec.append(temp_loss[0])


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

            print('step={}: A={}, b={}, Loss={}'.format(i+1, A.eval(), b.eval(), temp_loss))

     # step=300: A=[[0.7634046]], b=[[2.8413053]], Loss=[[5.382721]]

     # step=600: A=[[0.75245243]], b=[[3.7877374]], Loss=[[1.4977918]]

     # step=900: A=[[0.7403701]], b=[[4.3101645]], Loss=[[0.6288415]]

     # step=1200: A=[[0.72969586]], b=[[4.60605]], Loss=[[0.40883213]]

     # step=1500: A=[[0.72272784]], b=[[4.7734385]], Loss=[[0.3297159]]

    slope = A.eval()[0]

    cept = b.eval()[0]



더 자세히 알아보기 위해  시각화 하면

best_fit = []    

for i in x_vals.ravel():

    poly = i*slope + cept

    best_fit.append(poly)


_, ax = plt.subplots(1, 2)

ax[0].scatter(x_vals, y_vals, edgecolors='k', label='Data Points')

ax[0].plot(x_vals, best_fit, c='red', label='Best fit line', linewidth=3)

ax[0].legend(loc=2)

ax[0].set_title('Petal Width vs Sepal Length')

ax[0].set_xlabel('Petal Width')

ax[0].set_ylabel('Sepal Length')


ax[1].plot(loss_vec, c='k')

ax[1].set_title(regression_type + ' Loss per Generation')

ax[1].set_xlabel('Generation')

ax[1].set_ylabel('Loss')


plt.show()

LASSO Regression과 Loss함수



위의 코드를 사용자 정의 함수로 만들어 LASSO, Ridge를 살펴보겠습니다



위의 결과는 아래 코드로 확인할 수 있습니다.

my_regression_type(regression_type='LASSO', batch_size=50)

# step=300: A=[[0.764575]], b=[[2.5382898]], Loss=[[5.8621655]]

# step=600: A=[[0.7535565]], b=[[3.618642]], Loss=[[1.8615394]]

# step=900: A=[[0.7427662]], b=[[4.2173624]], Loss=[[0.7045775]]

# step=1200: A=[[0.7338138]], b=[[4.5521526]], Loss=[[0.44136143]]

# step=1500: A=[[0.72335386]], b=[[4.739038]], Loss=[[0.23825285]]

LASSO Linear Regression과 Loss



my_regression_type(regression_type='Ridge', batch_size=50)

# step=300: A=[[1.9796406]], b=[[1.416961]], Loss=[8.540436]

# step=600: A=[[1.7114378]], b=[[2.419876]], Loss=[5.517313]

# step=900: A=[[1.4033114]], b=[[3.132286]], Loss=[3.4445624]

# step=1200: A=[[1.1520133]], b=[[3.6732914]], Loss=[2.298217]

# step=1500: A=[[0.95343864]], b=[[4.086554]], Loss=[1.4839184]

Ridge Linear Regression과 Loss 




참고 자료: 

[1]TensorFlow Machine Learning Cookbook, Nick McClure

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

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

Logistic Regression  (0) 2018.05.01
Elastic Net Regression  (0) 2018.04.29
Deming Regression  (0) 2018.04.27
Loss Function in Linear Regressions  (0) 2018.04.26
TensorFlow Way of LinearRegression  (0) 2018.04.26

#!/usr/bin/env python3


Lasso


Lasso는 linear regression에 regularization을 적용하는 Ridge의 대안으로 사용됩니다.

Ridge와는 coefficient를 0에 가깝게 만들지만 Lasso는 coefficient를 0으로 만듭니다.

이 것을 L2 Regularization이라 합니다.

Lasso는 model을 이해하기 쉬워지고, 이 model의 가장 중요한 특성이 무엇인지 파악하기가 쉽습니다.

Lasso model을 통한 데이터분석은 다음과 같습니다.

from mglearn.datasets import load_extended_boston

from sklearn.model_selection import train_test_split

from sklearn.linear_model import Lasso, Ridge

import numpy as np


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)


lasso = Lasso().fit(x_train, y_train)


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

# 0.265


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

# 0.214


print(lasso.coef_)

# array([-0.        ,  0.        , -0.        ,  0.        , -0.        ,

#         0.        , -0.        ,  0.        , -0.        , -0.        ,

#        -0.        ,  0.        , -4.38009987, -0.        ,  0.        ,

#        -0.        ,  0.        , -0.        , -0.        , -0.        ,

#        -0.        , -0.        , -0.        , -0.        , -0.        ,

#        -0.        ,  0.        ,  0.        ,  0.        ,  0.        ,

#         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,

#         0.        ,  0.        ,  0.        , -0.        ,  0.        ,

#        -0.        , -0.        , -0.        , -0.        , -0.        ,

#        -0.        , -0.        , -0.        , -0.        ,  0.        ,

#         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,

#         0.        ,  0.        ,  0.        ,  0.        , -0.        ,

#        -0.        , -0.        , -0.        , -0.        , -0.        ,

#        -0.        , -0.        , -0.        ,  0.        ,  0.        ,

#         0.        , -0.        , -0.        , -0.        ,  0.        ,

#        -0.        , -0.        ,  0.        , -0.        , -0.        ,

#        -4.39984433, -0.        , -0.        ,  0.        , -0.        ,

#        -0.        , -0.        ,  0.        , -0.        , -0.44131553,

#        -0.        , -0.        , -0.        , -0.        , -0.        ,

#        -0.        , -0.        , -0.        , -0.        , -0.        ,

#        -0.        ,  0.        , -0.        , -0.        ])


print(np.sum(lasso.coef_ != 0))

# 3

Lasso는 train set와 test set 모두 결과가 좋지 않습니다. 즉 underfitting 되었다고 볼 수 있습니다.

105개의 특성중 3개만 사용했음을 알 수 있습니다.



Lasso에서 regularization parameter는 alpha입니다.

alpha를 줄이면 가장 낮은 오차를 찾아가는 반복횟수가 늘어나야 합니다. 따라서 max_iter를 증가시켜야 합니다.

alpha와max_iter값에 따른 Lasso결과를 시각화 해보겠습니다.

import matplotlib.pyplot as plt


alpha_set = [0.0001, 0.01, 1]

max_inter_set = [10000000, 100000, 1000]


train_score = []

test_score = []

used_feature = []


for a, m in zip(alpha_set, max_inter_set):

    lasso = Lasso(alpha=a, max_iter=m).fit(x_train, y_train)

    la_tr_score = round(lasso.score(x_train, y_train), 3)

    la_te_score = round(lasso.score(x_test, y_test), 3)

    number_used = np.sum(lasso.coef_ != 0)


    train_score.append(la_tr_score)

    test_score.append(la_te_score)

    used_feature.append(number_used)


index = np.arange(len(alpha_set))

bar_width = 0.35

plt.bar(index, train_score, width=bar_width, label='train')

plt.bar(index+bar_width, test_score, width=bar_width, label='test')

plt.xticks(index+bar_width/2, alpha_set) # bar그래프 dodge를 하기 위해 기준값에 보정치를 더해줍니다.


for i, (ts, te) in enumerate(zip(train_score, test_score)):

    plt.text(i, ts+0.01, str(ts), horizontalalignment='center')

    plt.text(i+bar_width, te+0.01, str(te), horizontalalignment='center')


plt.legend(loc=1)

plt.xlabel('alpha')

plt.ylabel('score')

plt.show()

alpha와 max_iter값에 따른 test 점수



사용된 특성은 다음과 같습니다.

index = np.arange(len(alpha_set))

plt.bar(index, used_feature)

plt.xticks(index, alpha_set)

for i, u in enumerate(used_feature):

    plt.text(i, u+1, str(u), horizontalalignment='center')

plt.xlabel('alpha')

plt.ylabel('used_feature')

plt.show()

alpha값에 따른 특성 사용 수

alpha 값을 낮추면 model의 complexity는 증가하여 train set의 성능이 좋아집니다.

그러나 너무 낮추게 되면 regularization의 효과가 없어져 overfitting 되므로 liner regression과 비슷해집니다.

Ridge의 alpha 범위는 0 < alpha < Inf

Lasso의 alpha 범위는 0 < alpha ≦ 1 과 같습니다.



다음으로 alpha 값이 다른 model들의 coefficient를 시각화 해보겠습니다.

n_feature = boston_data.shape[1]

line = np.linspace(0, n_feature, num=n_feature)

alpha_set = [0.0001, 0.01, 1]

max_iter_set = [10000000, 100000,1000]

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


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

plt.scatter(line, ridge.coef_, marker='o', label='Ridge alpha={}'.format(0.01))


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

    param = {'alpha':a, 'max_iter':i}

    lasso = Lasso(**param).fit(x_train, y_train) # **kwargs parameter

    plt.scatter(line, lasso.coef_, marker=m, label='Lasso alpha={}'.format(a))

    

plt.legend(ncol=2, loc=(0, 1.05))

plt.ylim(-25, 25)

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

plt.xlabel('coef_ list')

plt.ylabel('coef_ size')

plt.show()

alpha와 Ridge의 alpha값에 따른 특성의 값


Lasso alpha=1(빨강 정사각형)_일 때 계수 대부분이 0에 근접하였습니다.  ==> Regularization을 많이 했음을 의미합니다.

Lasso alpha=0.01(초록 정삼각형)일때 Regularization이 완화되어 분포가 약간 넓어진 것을 볼 수 있습니다.

Lasso alpha=0.00001(주황 역삼각형)일 때 Regularization이 거의 없어져 분포가 매우 넓어지는 것을 확인할 수 있습니다.

Ridge alapha=0.01(빨강 원)은 Lasso alpha=0.01과 분포가 비슷하지만 어떠한 계수도 0이 되지 않습니다.


보통은 Ridge Regression을 선호하지만 특성이 많고 일부분만 중요하다면 Lasso가 더 좋은 선택입니다.

분석하기 쉬운 model을 원하면 Lasso가 특성 중 일부만 사용하므로 쉡게 해석할 수 있는 model을 만듭니다.




참고 자료: 

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

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

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

+ Recent posts