다중공선성(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이 되지는 않음