Statictics & Math & Data Science/파이썬 데이터 분석

[Regression] Ridge and Lasso Regression in Python (3) - Lasso

Taewon Heo 2019. 1. 31. 20:11

[Regression] Ridge and Lasso Regression in Python (3) - Lasso


이번엔 Ridge Regression을 파이썬으로 구현해서 파라미터값에 따른 회귀식의 차이를 살펴보겠습니다.


L2와 L1 Regularization은 이전 포스팅의 내용을 참고해주세요.


1. 데이터를 생성합니다.


import numpy as np
import pandas as pd
from matplotlib.pylab import rcParams
rcParams['figure.figsize'] = 8, 5
from sklearn.linear_model import Ridge
import matplotlib.pyplot as plt

x = np.array([i*np.pi/180 for i in range(60, 300, 4)])
np.random.seed(10)
y = np.sin(x) + np.random.normal(0, 0.15, len(x))
data = pd.DataFrame(np.column_stack([x, y]), columns=['x', 'y'])
plt.plot(data['x'], data['y'], '.')
for i in range(2, 16): # power
colname = 'x_%d'%i #new var will be x_power
data[colname] = data['x']**i

2. 케이스를 구분하고 결과값을 저장할 테이블을 만듭니다.

Polynomial regression과 마찬가지로 predictors에 차수를 확장시켜 컬럼명(feature name)을 저장합니다.

파라미터값인 alpha_ridge를 케이스 별로 나눕니다.

# Initialize predictors to be set of 15 powers of x
predictors=['x']
predictors.extend(['x_%d'%i for i in range(2,16)])

# Set the different values of alpha to be tested
alpha_ridge = [1e-15, 1e-10, 1e-8, 1e-4, 1e-3,1e-2, 1, 5, 10, 20] #파라미터값인 alpha_ridge를 케이스 별로 나눕니다.

# Initialize the dataframe for storing coefficients.
col = ['rss', 'intercept'] + ['coef_x_%d'%i for i in range(1,16)]
ind = ['alpha_%.2g'%alpha_ridge[i] for i in range(0,10)]
coef_matrix_ridge = pd.DataFrame(index=ind, columns=col)

models_to_plot = {1e-15:231, 1e-10:232, 1e-4:233, 1e-3:234, 1e-2:235, 5:236}

3. Lasso regression 함수를 작성합니다.

여기서 추가로 필요한 파라미터는 alpha입니다. Ridge와 거의 같습니다.

def lasso_regression(data, predictors, alpha, models_to_plot):
# Fit the model
lassoreg= Lasso(alpha=alpha, normalize=True)
lassoreg.fit(data[predictors], data['y'])
y_pred = lassoreg.predict(data[predictors])

# Check if a plot is to be made for the entered alpha
if alpha in models_to_plot:
plt.subplot(models_to_plot[alpha])
plt.tight_layout()
plt.plot(data['x'], y_pred)
plt.plot(data['x'], data['y'], '.')
plt.title('Plot for alpha: %.3g'%alpha)

# Return the result in pre-defined format
rss = sum((y_pred-data['y'])**2)
ret = [rss]
ret.extend([lassoreg.intercept_])
ret.extend(lassoreg.coef_)
return ret

4. 결과 테이블을 계산합니다.

for i in range(10):
coef_matrix_ridge.iloc[i, ] = lasso_regression(data, predictors, alpha_ridge[i], models_to_plot)


계수를 보면 α값이 작을수록 계수값이 작습니다. Ridge와는 반대입니다. 그리고 α값이 큰 경우에 계수 값이 0이 되기도 합니다.

Lasso의 Cost function은 아래와 같습니다. 가중치의 절대값에 파라미터가 곱해져있는 형태입니다.



마찬가지로 미분을 해보면 좌극한에서는 -1, 우극한에서는 1의 기울기를 갖는데 0에서는 미분이 불가능합니다.


0에서 미분이 되지 않는 문제를 해결하는 방법인 Proximal gradient methods를 사용합니다. Sλt(x)는 Soft-thresholding operator라고 합니다.


S(x)를 x대신 w로 치환하여 아래의 g(wj)로 보면 됩니다. 꼭 람다가 λ/2가 되어야 하는 것은 아니고 그냥 λ여도 됩니다.(알고리즘의 차이인 걸로 추정됨)

즉, 미분이 안되는 미소 구간에 대해서는 가중치가 0이 된다는 뜻입니다.


미소구간을 결정하는 것은 λ이고 위의 Python 코드에서는 α입니다. 기울기가 큰 상태에서 큰 step(α)으로 기울기를 조정하는데 가중치의 크기가 +-α/2 구간으로 들어가게 되면 가중치가 0이 되어버립니다. 


또 다른 설명으로는, 가중치 제한인 s의 범위에 따른 해석입니다.

B-hat은 최소제곱자승법으로 구한 최소 지점입니다. s가 점점 커지다보면 B-hat에 도달하는데 이 지점은 파라미터가 0이되는 때입니다.

B-hat 주변의 타원은 RSS를 나타내는데 RSS와 파란색 영역이 닿는 부분이 계수값이 됩니다.




왼쪽 그림은 Lasso의 경우인데 Lasso는 어쩌다가 꼭지점에서 RSS가 최소가 될 수 있습니다. 그렇게 되면 그 B1의 가중치가 0이 될것입니다. 반면 오른쪽 그림의 Rigde는 원이기 때문에 축에서 만나지 않으므로 가중치가 0이되는 일이 없습니다.


도움이 되셨다면 공감 부탁드려요!