pythonML

[pythonML] 회귀- LinearRegression

독립성이 강한 ISFP 2022. 5. 9. 19:10
728x90
반응형

# LinearRegression 클래스

LinearRegression 클래스는 예측값과 실제값의 RSS 를 최소화해 OLS 추정 방식으로 구현한 클래스이다.

 

class sklearn.linear_model.LinearRegression(fit_intercept=True, normalize=False, copy_X=True,n_jobs=1)

 

-입력파라미터

fit_intercept : intercept(절편) 값을 계산할 것인지 말지를 지정함. (False이면 y축좌표가 0)

normalize:  True이면 회귀를 수행하기 전에 데이터 세트를 정규화 함.

 

-속성

coef_ : fit() 메서드를 수행했을 때 회귀 계수가 배열 형태로 저장되는 속성. shape =( Target값 개수, 피처 개수)

intercept_: intercept 값 (절편)

 

-다중 공선성문제 

: 입력 피처의 독립성에 많은 영향을 받아서 피처간의 상관관계가 매우 높은 경우 분산이 매우 커져서 오류에 민감함.

이 경우 독립적인 중요한 피처만 남기고 제거하거나 규제를 적용 or PCA를 통해 차원 축소 수행.

 

# 회귀 평가 지표 

: 실제 값과 회귀 예측값의 차이를 기반으로 한 지표가 중심

 

  • MAE : 실제 값과 예측값의 차이를 절대값으로 변환해 평균
  • MSE : 실제 값과 예측값의 차이를 제곱해 평균
  • RMSE : MSE 에 루트씌운 것
  • R2 : 예측값 분산/ 실제값 분산 (1에 가까울 수록 예측 정확도 높음)

 

이 밖에도 MSE RMSE 에 로그를 적용한 MSLE 와 RMSLE도 사용함.

BUT. 사이킷런은 RMSE 를 제공하지 않음. RMSE 를 구하기 위해 MSE에 루트를 씌워서 직접 만들어야 함.

 

그런데, cross_val_score , GridSearchCV 와 같은 scoring 함수에 회귀 평가 지표를 적용할 때 유의 할 점이 있음.

 

사이킷런 : 높은 지표 값일수록 좋은 모델 (그래서 음수를 갖는다)

회귀 : MSE 값이 낮을수록 좋은 회귀 모델

이기 때문에 

 

원래의 평가 지표 값에 -1 을 곱해서 음수를 만들어 작은 오류값이 더 큰 숫자로 인식하게 만든다

 

# 사이킷런 LinearRegression을 이용한 보스턴 주택 가격 예측

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from scipy import stats
from sklearn.datasets import load_boston
%matplotlib inline

# boston 데이타셋 로드
boston = load_boston()

# boston 데이타셋 DataFrame 변환 
bostonDF = pd.DataFrame(boston.data , columns = boston.feature_names)

bostonDF['PRICE'] = boston.target # boston.target : 주택 가격 (PRICE 컬럼으로추가)
print('Boston 데이타셋 크기 :',bostonDF.shape)
bostonDF.head()

 

 

# 'RM','ZN','INDUS','NOX','AGE','PTRATIO','LSTAT','RAD' 의 컬럼들이 각각 증가할 때 price(가격)은 어떻게 변화되는지 시각화

# 2개의 행과 4개의 열을 가진 subplots를 이용. axs는 4x2개의 ax를 가짐.
fig, axs = plt.subplots(figsize=(16,8) , ncols=4 , nrows=2)
lm_features = ['RM','ZN','INDUS','NOX','AGE','PTRATIO','LSTAT','RAD']
for i , feature in enumerate(lm_features):
    row = int(i/4) # 몫 (정수만)
    col = i%4      # 나머지
    
    # 시본의 regplot을 이용해 산점도와 선형 회귀 직선을 함께 표현
    sns.regplot(x=feature , y='PRICE',data=bostonDF , ax=axs[row][col])

=> 다른 컬럼들 보다 RM 과 LSTAT 의 PRICE  영향도가 가장 두드러지게 나타난다. 

RM (방 개수) : 양 방향의 선형성 (방 개수가 많을 수록 비싸다)

LSTAT (하위 계층의 비율) : 음 방향의 선형성 (하위 계층의 비율이 적을 수록 비싸다.)

 

 

# LinearRegression 클래스를 이용해 보스턴 주택 가격 평가

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error , r2_score

y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'],axis=1,inplace=False)

X_train , X_test , y_train , y_test = train_test_split(X_data , y_target ,test_size=0.3, random_state=156)

# Linear Regression OLS로 학습/예측/평가 수행. 
lr = LinearRegression()
lr.fit(X_train ,y_train ) #학습
y_preds = lr.predict(X_test) #예측
mse = mean_squared_error(y_test, y_preds) #평가
rmse = np.sqrt(mse)

print('MSE : {0:.3f} , RMSE : {1:.3F}'.format(mse , rmse)) # mse, rmse
print('Variance score : {0:.3f}'.format(r2_score(y_test, y_preds))) # R2

 

MSE : 17.297 , RMSE : 4.159
Variance score : 0.757

 

-절편, 회귀 계수

# f(x) = W1*X +W0 
print('절편 값:',lr.intercept_) # W0
print('회귀 계수값:', np.round(lr.coef_, 1)) # W1
절편 값: 40.995595172164336
회귀 계수값: [ -0.1   0.1   0.  3.  -19.8   3.4   0.  -1.7   0.4  -0.   -0.9   0. -0.6]

 

-회귀계수 내림차순 정렬

# 회귀 계수를 큰 값 순으로 정렬하기 위해 Series로 생성. index가 컬럼명에 유의
coeff = pd.Series(data=np.round(lr.coef_, 1), index=X_data.columns )
coeff.sort_values(ascending=False)
RM          3.4
CHAS        3.0
RAD         0.4
ZN          0.1
INDUS       0.0
AGE         0.0
TAX        -0.0
B           0.0
CRIM       -0.1
LSTAT      -0.6
PTRATIO    -0.9
DIS        -1.7
NOX       -19.8
dtype: float64

 

# cross_val_score로 최적화 후 보스턴 주택 가격 평가

from sklearn.model_selection import cross_val_score

y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'],axis=1,inplace=False)
lr = LinearRegression()

# cross_val_score( )로 5 Fold 셋으로 MSE 를 구한 뒤 이를 기반으로 다시  RMSE 구함. 
neg_mse_scores = cross_val_score(lr, X_data, y_target, scoring="neg_mean_squared_error", cv = 5) # 음수
rmse_scores  = np.sqrt(-1 * neg_mse_scores) # 양수로 변환후 루트로 다시 RMSE를 구함
avg_rmse = np.mean(rmse_scores)

# cross_val_score(scoring="neg_mean_squared_error")로 반환된 값은 모두 음수 
print(' 5 folds 의 개별 Negative MSE scores: ', np.round(neg_mse_scores, 2))
print(' 5 folds 의 개별 RMSE scores : ', np.round(rmse_scores, 2))
print(' 5 folds 의 평균 RMSE : {0:.3f} '.format(avg_rmse))
 5 folds 의 개별 Negative MSE scores:  [-12.46 -26.05 -33.07 -80.76 -33.31]
 5 folds 의 개별 RMSE scores :  [3.53 5.1  5.75 8.99 5.77]
 5 folds 의 평균 RMSE : 5.829 

 

728x90
반응형