Data Analysis/Machine Learning

Python_ML_Supervised_Multiple Regression

mansoorrr 2024. 1. 2. 13:26

다중회귀(Multiple Regression)

  • 독립변수가 여러개 있는 회귀분석을 의미
  • 여러개의 독립변수가 종속변수에 영향을 미치는 경우 다중회귀모형으로 데이터 표현 가능

$$ \widehat{Y}= \sum_{i=1}^n\beta_ix_i $$

 

  • 최적의 모델을 결정하기 위해 다양한 방법으로 변수를 선택
  • 모델이 복잡해지면 과대적합이 발생할 가능성이 있어 다양한 규제를 적용 가중치를 제한
  • 변수선택법을 통한 다항회귀 모델
    • 다중선형모델의 성능을 높이기 위해 독립변수의 부분집합을 선택하는 방법
    • 전진선택법 후진선택법으로 나뉨
    • 통계 기법에서 사용됨
구분 내용
전진선택법 단순 선형회귀에서 변수를 하나씩 추가 가며 모델의 정확도 높이는 방법
후진제거법 모든 변수 추가하고 유의하지 않은 변수들 제거하며 모델의 성능을 높이는 방법
단계적 선택법 변수를 추가 제거하며 모델의 성능을 높이는 방법
  • 규제를 통한 다항회귀 모델
    • 변수선택법의 대안으로 계수추정치들을 제한하거나 규칙화 하는 기법을 적용하여 독립변수를 모두 포함시킴
    • 규칙에 따라 계수 추정치들을 0으로 수축하는 방식으로 다중회귀모델의 성능 높임
    • 규제 방법으로 릿지(L1), 라쏘(L2), 엘라스틱넷 이 있음

[릿지(Ridge)]

  • MSE(training accuracy)에 Genalization accuracy(일반화: 규제항)항을 추가하여 overfitting을 방지한다.

$$ RidgeMSE(\beta) = MSE(\beta) + a1/2\sum_{i=1}^n\beta^2_i $$

 

  • a = 0이면 선형회귀의 mse와 동일하다
  • a가 커질수록 규제가 강하게 들어가며 variance가 감소하게 되고 overfitting에서 벗어나게 된다
  • 변수선택법에 비해 속도도 빠르다.
  • 크기가 큰 변수를 우선적으로 줄이는 경향이 있음
  • sklearn.linear_model.Ridge(parameters)
Parameter
alpha - default=1.0
- 정규화 강도를 정하는 값
- 소수점이어야 하며, 값이 커질수록 정규화의 강도가 세짐
fit_intercept - default=True
- 절편 계산할지 여부
- False: 절편을 사용하지 않는 모델로 계산
normalize - default=False
- True: (X-평균) / L2-norm 회귀 전에 정규화 함.
- 보통 False로 놓고 외부에서 StandardScaler사용해서 정규화 진행
positive - default=False
- True: 계수가 양수가 됨
copy_X - default=True(X복사)
- False: X 덮어씀
Property
coef_ - 추정된 회귀 계수
intercept_ - 절편
Method
fit(X, y) - 학습
- X: train data( 2차원)
- y: train target data
get_params([deep]) - 모델의 파라미터 가져옴
- 딕셔너리 형태로 반환
predict(X) - 모델을 사용해 예측
- X: test data(2차원)
score(X, y) - 모델의 결정계수(모델성능)
- X: test data(2차원)
- y: test target data

 

예제 1) 당뇨 데이터를 통해 릿지 회귀 수행

  • 릿지 회귀를 수행하고 a값에 따라 회귀계수의 변화를 시각화 한다.
  • sklearn에서 제공하는 diabetes 데이터를 로드하여 기본 정보를 확인한다.
  • 442개 데이터에 11개 변수이다.
  • 변수별 결측치는 없다.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

from sklearn.datasets import load_diabetes

# 데이터 로드
data = load_diabetes()

df = pd.DataFrame(data.data, columns=data.feature_names)
df["target"] = data.target
print(df.shape)
df.head()

 

  • 데이터를 분할하고 Ridge 모델의 alpha값을  조정해서 회귀계수를 산출한다.
  • a값은 np.logspace를 통해 생성한다.
from sklearn.linear_model import Ridge


#---------- 데이터 분할
X = df.drop(["target"], axis=1)
y = df["target"]

#---------- a정의
alpha = np.logspace(-3, 1, 5)
alpha

#---------- 회귀실시
ridge_coef = []
for a in alpha:
  ridge = Ridge(alpha=a)
  ridge.fit(X, y)
  ridge_coef.append(ridge.coef_)
  
# a값에 따른 데이터 프레임 생성
ridge_df = pd.DataFrame(ridge_coef, columns=X.columns, index=alpha)
ridge_df

 

  • a값의 변화에 따라 회귀계수가 변화하는 모습을 확인한다.
  • a값이 커지면 정규화 강도가 커지므로 회귀계수가 0에 수렴하게 되고
  • a값이 0이면 mse와 동일하다
#a값 변화에 따라 시각화
plt.figure()
plt.semilogx(ridge_df)
plt.legend(labels=ridge_df.columns, bbox_to_anchor=(1,1))
plt.title("Ridge")
plt.xlabel("alpha")
plt.ylabel("Coef")
plt.axhline(y=0, linestyle="--", color="black", linewidth=2)
plt.show();

 

  • 회귀분석과 비교한다.
  • a가 0이면 mse를 활용한 모델의 계수와 비슷해 짐을 확인할 수 있다.
lr = LinearRegression()
lr.fit(X, y)

linear_coef = lr.coef_

plt.axhline(y=0, linestyle="--", linewidth=2, color="black")
plt.plot(ridge_df.loc[0.001], "^-", linewidth=3, label="Ridge alpha = 0.001")
plt.plot(ridge_df.loc[0.010], "o-", label="Ridge alpha = 0.010")
plt.plot(ridge_df.loc[0.100], ":", label="Ridge alpha = 0.100")
plt.plot(ridge_df.loc[1.000], "v-", label="Ridge alpha = 1.000")
plt.plot(ridge_df.loc[10.000], "*--", label="Ridge alpha = 10.000")
plt.plot(linear_coef, "r-", linewidth=3, label="LinearRegression")

plt.xlabel("x")
plt.ylabel("coef")
plt.legend(bbox_to_anchor=(1,1))
plt.show();

[라쏘(Lasso)]

  • 변수의 개수가 매우 많은 데이터로 릿지 모델을 실행시키면 결과 해석의 문제가 있음

$$ RidgeMSE(\beta) = MSE(\beta) + a\sum_{i=1}^n|{\beta_i}| $$

  • 라쏘의 수축패널티는 $\beta_i$가 0에 가까울때 작으므로 $/beta_i$의 추정치를 0으로 수축하는 효과를 줌
  • 단, a가 충분히 클때, 계수 추정치들의 일부 0이 되게 할 수 있음(덜 중요한 변수는 가중치를 제거할 수 있다는 점이 릿지와의 차이점)
  •  회소(sparse) 모델을 만들 수 있음
  • 변수 간 상관관계가 높을 경우 ridge에 비해 예측성능 떨어짐
  • sklearn.linear_model.Lasso(parameters)
Parameter(릿지와 동일)
alpha - default=1.0
- 정규화 강도를 정하는 값
- 소수점이어야 하며, 값이 커질수록 정규화의 강도가 세짐
- 0일 경우 OLS기반 회귀와 동등한 결과 도출
fit_intercept - default=True
- 절편 계산할지 여부
- False: 절편을 사용하지 않는 모델로 계산
normalize - default=False
- True: (X-평균) / L2-norm 회귀 전에 정규화 함.
- 보통 False로 놓고 외부에서 StandardScaler사용해서 정규화 진행
positive - default=False
- True: 계수가 양수가 됨
copy_X - default=True(X복사)
- False: X 덮어씀
Property(릿지와 동일)
coef_ - 추정된 회귀 계수
intercept_ - 절편
Method(릿지와 동일)
fit(X, y) - 학습
- X: train data( 2차원)
- y: train target data
get_params([deep]) - 모델의 파라미터 가져옴
- 딕셔너리 형태로 반환
predict(X) - 모델을 사용해 예측
- X: test data(2차원)
score(X, y) - 모델의 결정계수(모델성능)
- X: test data(2차원)
- y: test target data

 

예시 1) 당뇨 데이터를 통해 라쏘 회귀 수행

  • 릿지 때와 동일하게 a값을 생성하여 a별 lasso를 적용한다.
  • a는 np.logspace를 사용한다.
  • 모델을 만들고 a별 도출된 회귀계수를 확인한다.
  • 데이터프레임으로 봤을때도 특정 변수들의 회귀계수를 0으로 만드는 것을 확인할 수 있다.
  • 시각화 해보면 a값이 커질수록 회귀계수가 점점 0이 되는 것을 확인 가능하다.
from sklearn.linear_model import Lasso

lasso_alpha = np.logspace(-3, 1, 5)
lasso_coef = []
for alpha in lasso_alpha:
  lasso = Lasso(alpha=alpha)
  lasso.fit(X, y)
  lasso_coef.append(lasso.coef_)
  
lasso_df = pd.DataFrame(lasso_coef, columns=X.columns, index=lasso_alpha)
lasso_df

 

  • MSE를 활용한 LinearRegression과 비교 진행
  • alpha가 작은 라쏘 모델의 회귀 계수는 MSE를 활용한 LinearRegression의 회귀계수와 비슷하다.
  • 또한 alpha가 커지면서 회귀계수는 0이 되었다.
lr = LinearRegression()
lr.fit(X, y)

lr_coef = lr.coef_

plt.plot(lasso_df.loc[0.001], "^-", label="Lasso alpha = 0.001")
plt.plot(lasso_df.loc[0.010], "o-", label="Lasso alpha = 0.010")
plt.plot(lasso_df.loc[0.100], "*-", label="Lasso alpha = 0.100")
plt.plot(lasso_df.loc[1.000], ":", label="Lasso alpha = 1.000")
plt.plot(lasso_df.loc[10.000], "^--", label="Lasso alpha = 10.000")
plt.plot(lr_coef, label="LinearRegression", linewidth=2)
plt.axhline(y=0, linestyle="--", linewidth=2, color="black")
plt.legend(bbox_to_anchor=(1,1))
plt.show();

 

 

[엘라스틱넷(Elasticnet)]

  • 엘라스틱넷은 릿지와 라쏘를 절충한 알고리즘
  • 수축패널티는 릿지와 라쏘를 단순히 더함
  • 혼합비율 r을 활용해 조절(r=0이면 릿지와 같고, r=1이면 라쏘와 같음)
  • sklearn.linear_model.ElasticNet(parameters)
Parameter
alpha - default=1.0
- 정규화 강도를 정하는 값
- 소수점이어야 하며, 값이 커질수록 정규화의 강도가 세짐
- 0일 경우 OLS기반 회귀와 동등한 결과 도출
fit_intercept - default=True
- 절편 계산할지 여부
- False: 절편을 사용하지 않는 모델로 계산
normalize - default=False
- True: (X-평균) / L2-norm 회귀 전에 정규화 함.
- 보통 False로 놓고 외부에서 StandardScaler사용해서 정규화 진행
positive - default=False
- True: 계수가 양수가 됨
copy_X - default=True(X복사)
- False: X 덮어씀
Property
coef_ - 추정된 회귀 계수
intercept_ - 절편
Method
fit(X, y) - 학습
- X: train data( 2차원)
- y: train target data
get_params([deep]) - 모델의 파라미터 가져옴
- 딕셔너리 형태로 반환
predict(X) - 모델을 사용해 예측
- X: test data(2차원)
score(X, y) - 모델의 결정계수(모델성능)
- X: test data(2차원)
- y: test target data

 

 

예시 1) 당뇨데이터를 통해 엘라스틱넷 회귀 수행

  • alpha값 조정하여 위와 동일하게 진행
  • elasticnet또한 alpha가 증가하면서 0으로 수렴하는 것을 확인할 수 있다.
from sklearn.linear_model import ElasticNet

ela_alpha = np.logspace(-3, 1, 5)

ela_coef = []
for alpha in ela_alpha:
  ela = ElasticNet(alpha=alpha)
  ela.fit(X, y)
  ela_coef.append(ela.coef_)

ela_df = pd.DataFrame(ela_coef, columns=X.columns, index=ela_alpha)

plt.semilogx(ela_df)
plt.axhline(y=0, color="black", linewidth=2, linestyle="--")
plt.title("ElasticNet")
plt.xlabel("alpha")
plt.ylabel("coef")
plt.legend(labels=ela_df.columns, bbox_to_anchor=(1,1))

 

  • LinearRegression과 비교를 진행한다
  • alpha값이 커지면서 회귀계수는 0이 된다.
  • alpha값이 0이면 LinearRegression과 비슷한 회귀계수를 갖는다.
plt.plot(ela_df.loc[0.001], "^-", label="Elastic alpha = 0.001")
plt.plot(ela_df.loc[0.010], "o-", label="Elastic alpha = 0.010")
plt.plot(ela_df.loc[0.100], "*-", label="Elastic alpha = 0.100")
plt.plot(ela_df.loc[1.000], ":", label="Elastic alpha = 1.000")
plt.plot(ela_df.loc[10.000], "^--", label="Elastic alpha = 10.000")
plt.plot(lr_coef, label="LinearRegression", linewidth=2)
plt.axhline(y=0, linestyle="--", linewidth=2, color="black")
plt.legend(bbox_to_anchor=(1,1))
plt.show();