ML

[ML] 다중공선성 | SVD-OLS | Over fitting | 랏쏘회귀, 릿지회귀

ha_data 2024. 2. 1. 20:36

다중공선성(Multicollinearity)

입력 데이터가 갖고 있는 특징값들 사이에 상관 관계가 존재할 때 발생하는 문제 상황

-> 이 상황에서는 머신 러닝 모델이 작은 데이터 변화에도 민감하게 반응

-> 안정성과 해석력 저하시킴

정규 방정식으로 해를 구하는 상황에서 치명적인 문제 발생.

이를 해결하기 위해 SVD-OLS 라는 회피 방법이 존재 

 

SVD-OLS란 SVD를 사용해 선형 회귀 모델의 해를 구하는 방법

학습 데이터를 모아둔 행렬 X에 SVD를 적용해 특이값 분해 -> X에 OLS 방식의 풀이 적용

대신 SVD 계산으로 인한 시간 소요가 늘어남.

Scikit-learn 패키지 안의 선형 회귀 알고리즘은 SVD 류의 방식으로 구현되어 있음

# 서로 상관 관계가 깊은 두 독립변수 x1과 x2를 생성
# x2 = x1

num_data = 100
noise = np.random.normal(0, 3, num_data)

w0_col = -0.5
w1_col = 1.8
w2_col = 3.3

# 데이터 생성.x1_col=x2_col 강한 상관관계가 있음
x1_col = np.linspace(0, 10, num_data)
x2_col = x1_col
y_col = w0_col + w1_col * x1_col + w2_col * x2_col + noise

X_col = np.stack([np.ones_like(x1_col), x1_col, x2_col], axis=1)

# 정규 방정식의 방식으로 문제를 해결하는 과정에서
# 계산되어야 하는 np.linalg.inv(X.T @ X)의 계산이 안됨
print(np.linalg.inv(X_col.T @ X_col))
     87 
     88 def _raise_linalgerror_singular(err, flag):
---> 89     raise LinAlgError("Singular matrix")
     90 
     91 def _raise_linalgerror_nonposdef(err, flag):

LinAlgError: Singular matrix

 

강한 상관관계가 있는 두 변수 x1_col, x2_col 데이터를 생성

=> Singular matrix 에러 발생 

 

SVD_OLS로 해결

# SVD-OLS 방식을 이용한 선형 모델 풀이
# w = V @ SIGMA-1 @ U^T @ y

def calc_SVDOLS(X, y):
    # svd를 적용해 U, SIGMA, V^T(Vt)를 구함
    U, s, Vt = np.linalg.svd(X, full_matrices=False)
    SIGMA = np.diag(s)

    # SVD-OLS 수식 적용
    w_svdols = Vt.T @ np.linalg.inv(SIGMA) @ U.T @ y
    return w_svdols

w_svdols = calc_SVDOLS(X, y)
w_ols = calc_OLS(X, y)

print('SVD OLS로 예측한 w0 : ', w_svdols[0])
print('SVD OLS로 예측한 w1 : ', w_svdols[1])
print('-'*50)

print('OLS로 예측한 w0 : ', w_ols[0])
print('OLS로 예측한 w1 : ', w_ols[1])
print('-'*50)

print('실제 w0 : ', w0)
print('실제 w1 : ', w1)
 
SVD OLS로 예측한 w0 : 2.5086792318291633
SVD OLS로 예측한 w1 : 3.4793315235094275
--------------------------------------------------
OLS로 예측한 w0 : 2.508679231829176
OLS로 예측한 w1 : 3.479331523509426
--------------------------------------------------
실제 w0 : 2.3 실제 w1 : 3.5

SVD OLS 결과 값 = OLS 수식적으로 동일함. 

 

해를 구할 수 없던 OLS와 다르게 해 도출 가능

w_svdols = calc_SVDOLS(X_col, y_col)

print('SVD OLS로 예측한 w0 : ', w_svdols[0])
print('SVD OLS로 예측한 w1 : ', w_svdols[1])
print('SVD OLS로 예측한 w2 : ', w_svdols[2])
print('-'*50)

print('실제 w0 : ', w0_col)
print('실제 w1 : ', w1_col)
print('실제 w2 : ', w2_col)
SVD OLS로 예측한 w0 : -0.24271753635545057
SVD OLS로 예측한 w1 : 913269366762999.0
SVD OLS로 예측한 w2 : -913269366762993.5
--------------------------------------------------
실제 w0 : -0.5 실제 w1 : 1.8 실제 w2 : 3.3

 

해는 존재하지만 값은 정답과 거리가 있음

 

다중공선성이 없는 경우  - 여러 방법으로 해 구한 뒤 결과 비교

from sklearn.linear_model import LinearRegression

w_svdols = calc_SVDOLS(X, y)
w_ols = calc_OLS(X, y)
w_SGD = calc_SGD(x, y, lr, epochs, init_params)
linear_reg = LinearRegression()
linear_reg.fit(X, y)

OLS로 예측한 w0 : 2.508679231829176

OLS로 예측한 w1 : 3.479331523509426

정규방정식

--------------------------------------------------

SVD OLS로 예측한 w0 : 2.5086792318291633

SVD OLS로 예측한 w1 : 3.4793315235094275

--------------------------------------------------

SGD로 예측한 w0 : 2.508617090523525

SGD로 예측한 w1 : 3.479340867087513

경사하강법

--------------------------------------------------

내장 함수로 예측한 w0 : 2.508679231829163

내장 함수로 예측한 w1 : 3.4793315235094293

TSVD-OLS로 구성

--------------------------------------------------

실제 w0 : 2.3 실제 w1 : 3.5

 

공선성이 없으므로 여러 방식으로 구한 결과 값이 서로 비슷함

내장 함수를 쓸 경우 TSVD-OLS를 사용하기 때문에 데이터 일부를 누락시키고 문제를 품. 실제 정답과 차이가 있을 수 있음

 

과적합 문제(Over-fitting)

머신러닝 모델이 피해야 되는 중요한 문제

모델이 학습 데이터에 너무 집중해 일반화가 떨어지는 상황

파라미터인 w값이 매우 커지게 됨. 따라서, w값이 너무 커지지 않도록 규제(regulation)를 가해 과적합 문제 회피

규제를 준 방식

- 라쏘 회귀

- 릿지 회귀

 

어떻게 규제를 줘서 w를 작게 했을까?

라쏘 회귀

라쏘 회귀에 사용되는 L1 규제는 일부 파라미터의 값을 완전히 0으로 만들 수 있음

이를 통해 모델이 사용하는 데이터 특성 중 불필요한 특성을 무싷는 효과를 가져올 수 있음

 -> 모델이 단순화되어 해석이 용이함

변수가 많고, 일부의 변수가 중요한 역할을 하는 경우 활용될 수 있음

 

릿지 회귀

릿지 회귀에 사용되는 L2 규제는 파라미터 값을 적당히 작게 만듦

0에 가까운 값이지만 0이 되지는 않음