본문 바로가기

전공

Scikit-learn(사이킷런)으로 선형회귀

Scikit-learn で線形回帰의 번역본.

링크

https://qiita.com/0NE_shoT_/items/08376b08783cd554b02e

 

Scikit-learn で線形回帰 - Qiita

はじめに 売り上げなどの数量(連続値をとる目的変数)を予測するのに役立つのが回帰です。この記事では、特に目的変数と説明変数の関係をモデル化する一つの方法である線形回帰をScikit

qiita.com

여러 수식을 표기하고 있기 때문에, 모바일 버전에서 보는 것보다, PC버전에서 보는 것이 적합합니다.

편의상 목적변수는 종속변수로, 설명변수는 독립변수로 써두겠읍니다..


시작하며


매출 등의 수량(연속치를 취하는 종속변수)을 예측하는 데에 도움이 되는 회귀입니다.

이 기사에서는 특히 종속변수와 독립변수의 관계를 모델화하는 하나의 방법으로서의 선형회귀를

Scikit-learn 라이브러리를 실행해 진행하는 방법에 대해서, 비망록으로서 써두겠습니다.

 

Scikit-learn에 대해서


Scikit-learn은 Python의 기계학습 라이브러리 중 하나입니다.

 

scikit-learn: machine learning in Python — scikit-learn 0.23.2 documentation

Model selection Comparing, validating and choosing parameters and models. Applications: Improved accuracy via parameter tuning Algorithms: grid search, cross validation, metrics, and more...

scikit-learn.org

 

선형회귀에 대해서


선형회귀는, 연속값을 취하는 종속변수 \(y\)와 독립변수 \(x\) (특징량)의 선형관계를 모델화합니다.

선형관계라는 것은, 알기쉽게 말하면 독립변수가 증가(감소)하는 것에 따라, 목적변수도 단조롭게 증가(감소)하는 관계입니다.

독립변수가 하나일 경우 (단회귀라고 말함), 종속변수와 독립변수의 관계를 모델화하는 선형 모델은 이하의 식으로 정의됩니다.

$$y = w_0 + w_1x$$

여기서 가중치 \(w_0\)은 절편, 가중치 \(w_1\)은 독립변수의 계수를 나타냅니다. 

선형회귀의 목적은, 독립변수와 종속변수의 관계를 표현하는 선형 모델의 가중치를 학습하는 것입니다.

위의 식처럼, 종속변수가 독립변수의 일차식에서 표현될 때,

선형회귀는 "독립변수와 종속변수의 산포도에서, 데이터의 분포를 가장 잘 특징짓는 직선을 찾아내는 것" 이라고 말할 수 있습니다.

 

독립변수가 여러 개인 상황 (중(重)회귀라고 말함), 종속변수를 독립변수의 선형화에서 표현하는 선형 모델은 아래 식으로 정의됩니다.

$$y = w_0x_0 + w_1x_1 + \cdots +w_mx_m = \sum^m_{i=0}w_ix_i$$

여기서, 가중치  \(w_0\)은 \(x_0=1\) 로서 절편을 나타냅니다.

중회귀는 단회귀를 여러 개의 독립변수를 다룰 수 있게 일반화시킨 것으로,

종속변수와 여러개의 독립변수의 관계를 나타내는 모델의 중첩을 학습하는 것이 목적입니다.

 

선형회귀 모델


Scikit-learn으로 선형회귀를 하는 것에는, linear_model의 LinearRegression 모델을 사용합니다.

(공식 문서 : http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html )

주로 이용하는 메소드는 아래와 같습니다.

 

  • fit 메소드:선형 모델의 가중치를 학습
  • predict 메소드:선형 모델로부터 종속변수를 예측
  • score 메소드:결정계수 (선형 모델이 어느정도의 종속변수를 설명할 수 있는가) 를 출력

여기서는, UCI Machine Learing Repository (http://archive.ics.uci.edu/ml/index.php) 에서 공개되어있는,

 

보스턴시 교외의 지역별 주택가격 (https://archive.ics.uci.edu/ml/machine-learning-databases/housing/)을 사용합니다.

 

Index of /ml/machine-learning-databases/housing

 

archive.ics.uci.edu

아래의 코드에서는, Scikit-learn 라이브러리 부속 데이터셋을 읽어들여, Pandas의 DataFrame으로 교환합니다.

(이후 코드의 동작환경은, Python 3.7.3, Pandas 0.24.2, Scikit-learn 0.20.3 입니다.)

 

from sklearn.datasets import load_boston
boston = load_boston() # 데이터세트를 읽어들임

import pandas as pd
boston_df = pd.DataFrame(boston.data, columns = boston.feature_names) # 독립변수(boston.data)를 DataFrame에 저장
boston_df['MEDV'] = boston.target # 종속변수(boston.target)도 DataFrame에 추가

 

데이터를 들여다보면, 이런 느낌입니다.

 

boston_df.head()

 

 

 

각 변수 (데이터 항목) 의 설명은 아래와 같습니다.

 

변수 설명
CRIM 범죄 발생률
ZN 25000 평방 피트 이상의 주택 구역 비율
INDUS 비소매업종의 토지면적 비율
CHAS 찰스강변인가를 나타내는 더미 변수
NOX 질소산화물의 농도
RM 평균 방(room)의 개수
AGE 1940년 전에 지어진 건물의 비율
DIS 다섯개의 보스턴 고용시설으로의 거리
RAD 고속도로 접근 용이성
TAX 10,000 달러당 부동산세율
PTRATRIO 학생과 교사의 비율
B 흑인의 비율
LSTAT 저소득자의 비율
MEDV 주택가격의 중앙값 (1,000 단위)

 

여기서, 만약 아래의 코드를 사용해서 RM (평균 방의 개수) 와 MEDV (주택가격) 의 관계를 보면,

대개 선형관계에 있는, 즉 평균 방 개수가 많을수록 주택가격도 높아진다고 보입니다.

 

import matplotlib.pyplot as plt
%matplotlib inline
plt.scatter(boston_df['RM'], boston_df['MEDV']) # 평균 방 개수와 주택가격의 산포도를 플로트(plot)

plt.title('Scatter Plot of RM vs MEDV')    # 그래프의 제목
plt.xlabel('Average number of rooms [RM]') # x축의 라벨
plt.ylabel('Prices in $1000\'s [MEDV]')    # y축의 라벨
plt.grid()                                 # 그리드 선을 표시

plt.show()                                 # 그래프를 표시

 

 

 

Pandas의 corr() 메소드로 평균 방 개수와 주택가격의 상관계수를 산출해보면, 약 0.7 정도로 양의 상관계수가 있단 것을 알 수 있습니다.

 

 

 

이후에는, 주택가격 (종속변수)과 평균 방의 개수 (독립변수)의 관계를 표현하는 선형회귀 모델을 구축해보겠습니다.

 

선형회귀 모델의 구축


fir 메소드에서 가중치를 학습하는 것으로, 선형회귀 모델을 구축합니다.

학습할 때에는, 독립변수 \(x\) 와 종속변수 \(y\)에는 NumPy 배열을 이용하기 위해, values 속성으로 독립변수와 종속변수의 열(列)로부터 NumPy의 배열을 꺼내고 있습니다.

 

from sklearn.linear_model import LinearRegression
lr = LinearRegression()

X = boston_df[['RM']].values         # 독립변수(NumPy의 배열)
Y = boston_df['MEDV'].values         # 종속변수(Numpy의 배열)

lr.fit(X, Y)                         # 선형 모델의 가중치를 학습

 

학습으로부터 얻어낸, 선형 모델의 절편 \(w_0\) 은 intercept_ 속성으로, 독립변수의 계수 \(w_1\) 은 coef_ 속성으로 격납됩니다.

학습결과를 확인해보면, 계수는 약 9.1, 절편은 약 -34.7인 것을 알 수 있습니다.

 

print('coefficient = ', lr.coef_[0]) # 독립변수의 계수를 출력
print('intercept = ', lr.intercept_) # 절편을 출력

coefficient =  9.10210898118
intercept =  -34.6706207764

 

학습으로 얻어낸 절편과 계수를 이용해, 회귀직선을 그어보겠습니다.

회귀 직선을 플로트(plot, 작도)하기 위해서는, 선형 모델에 독립변수의 값을 부여했을 때의 종속변수의 값 (예측값)이 필요합니다.

이것을 얻기 위해서 predict 메소드를 이용하고 있습니다.

 

plt.scatter(X, Y, color = 'blue')         # 독립변수와 종속변수의 데이터 점의 산포도를 플로트
plt.plot(X, lr.predict(X), color = 'red') # 회귀직선을 플로트

plt.title('Regression Line')               # 그래프의 제목
plt.xlabel('Average number of rooms [RM]') # x축의 라벨
plt.ylabel('Prices in $1000\'s [MEDV]')    # y축의 라벨
plt.grid()                                 # 그리드선을 표시

plt.show()                                 # 그래프 표시

 

주어진 데이터 점에 어느정도 맞는 회귀직선을 그은 것을 확인할 수 있습니다.

 

 

 

 

선형회귀 모델의 성능평가


학습으로 얻어낸 선형 모델의 성능을 평가하려면, 학습에서는 쓰고있지 않은 데이터로 모델을 검증하는 것이 필요합니다.

구축한 모델을 앞으로 이용하는 (예 : 매상 예측 모델의 예측결과를 사용해 비지니스 계획을 책정하거나, 어떤 시책을 펼쳐나갈 때) 것을 고려하면, 모델의 구축시에는 얻을 수 없는 장래의 데이터에 대해 높은 정밀도로 예측 할 수 있는 것이 중요하기 때문입니다.

그걸 위해서는, 먼저 수중의 데이터를 학습데이터와 검증 데이터로 나눕니다.

그리고, 학습 데이터로 모델을 구축해, 검증 데이터를 장래의 데이터와 진단하고, 이것에 대한 모델의 성능(범화성능이라고 말함)을

평가합니다.

 

아래의 코드에서는 model_selection의 train_test_split을 이용해, 데이터를 학습용과 검증용 7:3의 비율로 분할해 

학습 데이터를 사용해 선형 모델을 구축해보겠습니다.

(공식 문서 : http://scikitlearn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html )

 

from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, train_size = 0.7, test_size = 0.3, random_state = 0) # 데이터를 학습용과 검증용으로 분할

lr = LinearRegression()
lr.fit(X_train, Y_train) # 선형 모델의 가중치를 학습

 

선형회귀 모델의 성능평가에는 주로 아래의 방법 · 지표를 이용합니다.

 

  • 편차 플로트 (plot):잔차 (종속변수의 참값과 예측값의 차분)을 가시화
  • 평균 제곱 오차:잔차평방화를 데이터 수로 정시화(正視化)한 값
  • 결정계수:상관계수의 제곱

잔차 플로트(plot)는, 잔차 (종속변수의 참값과 예측값의 차분)의 분포를 가시화한 것입니다.

선형 모델이 종속변수를 완벽하게 예측가능한 상황은 잔차가 0이 되는 것으로, 예측 정밀도가 좋은 선형 모델의 잔차 플로트는, 0을 중심으로 랜덤하게 흩어진 것입니다.

잔차 플로트에 무언가 패턴이 보이는 경우는, 선형 모델에서 설명할 수 없는 정보가 있다는 것을 시사합니다.

아래의 코드는, 잔차 플로트를 묘화합니다.

*묘화 - 그림을 그림

 

Y_pred = lr.predict(X_test) # 검증 데이터를 사용해 종속변수를 예측

plt.scatter(Y_pred, Y_pred - Y_test, color = 'blue')      # 잔차를 플로트
plt.hlines(y = 0, xmin = -10, xmax = 50, color = 'black') # x축에 따른 직선을 플로트
plt.title('Residual Plot')                                # 그래프의 제목
plt.xlabel('Predicted Values')                            # x축의 라벨
plt.ylabel('Residuals')                                   # y축의 라벨
plt.grid()                                                # 그리드 선을 표시

plt.show()                                               # 그래프를 표시

 

잔차 플로트를 보면, 잔차는 0을 중심으로 분포하고 있습니다만, 선형 모델에서 설명할 수 없는 패턴도 있는 것처럼 보입니다.

 

 

 

 

평균 제곱 오차는, 잔차의 평방화를 데이터 수로 정시화한 것으로, 모델의 성능을 수치화하는 것에 도움이 됩니다.

물론, 오차가 작으면 작을수록 모델의 성능은 좋다고 말할 수 있습니다.

평균 제곱 오차는, metrics의 mean_squared_error를 이용하는 것으로 산출이 가능합니다.

 

from sklearn.metrics import mean_squared_error

Y_train_pred = lr.predict(X_train) # 학습데이터에 대한 종속변수를 예측
print('MSE train data: ', mean_squared_error(Y_train, Y_train_pred)) # 학습 데이터를 사용했을 때의 평균 제곱 오차를 출력
print('MSE test data: ', mean_squared_error(Y_test, Y_pred))         # 검증 데이터를 사용했을 때의 평균 제곱 오차를 출력

 

학습 데이터, 검증 데이터 각각을 사용했을 때의 평균 제곱 오차를 비교하면, 검증 데이터를 사용했을 때의 오차가 더 컸다는 걸 알 수 있습니다.

이것으로, 구축한 선형 모델은 학습 데이터에 너무 적응하고(맞고) 있다는 (과(過)학습이라고 말함) 것을 시사합니다.

 

MSE train data:  42.1576508631
MSE test data:  47.0330474798

 

결정계수도, 선형 모델의 예측 오차를 반응한 지표이며, 값이 클수록 선형 모델이 데이터에 맞고(적응하고) 있다고 말할 수 있습니다. 

결정계수는, metrics의 r2_score를 이용하는 것으로 산출이 가능합니다.

또, LinearRegression 모델의 score 메소드도 산출이 가능합니다.

 

from sklearn.metrics import r2_score

print('r^2 train data: ', r2_score(Y_train, Y_train_pred))
print('r^2 test data: ', r2_score(Y_test, Y_pred))

 

학습 데이터, 검증 데이터 각각을 사용했을 때의 결정계수를 비교하면, 검증 데이터를 사용했을 때의 결정계수 쪽이 작다는 것을 알 수 있습니다.

이것으로도, 구축한 선형 모델에는 과학습이 일어나고 있다는 것을 알 수 있습니다.

 

r^2 train data:  0.502649763004
r^2 test data:  0.435143648321

 

여기까지는 단회귀의 코드 예시를 나타내고 있었습니다만, 중회귀의 상황도 간단히 시험해보는 것이 가능합니다.

만약, 주택가격 (종속변수)와, 평균 방의 개수 및 저소득자의 비율 (독립변수)의 관계를 표현하는 선형회귀 모델은, 아래와 같은 코드로 구축하는 것이 가능합니다.

 

lr = LinearRegression()

X = boston_df[['RM', 'LSTAT']].values         # 독립변수(NumPy 배열)
Y = boston_df['MEDV'].values         # 종속변수(NumPy 배열)

lr.fit(X, Y)                         # 선형회귀 모델의 가중치를 학습

 

끝으로


이 기사에서는, Scikit-learn 라이브러리로 선형회귀를 하는 방법에 대해서 간단히 살펴봤습니다.

종속변수를 정밀도 높게 표현하는 선형 모델을 구축하기 위해서는, 특징량 (독립변수) 선택이나 정규화를 시행하는 걸 검토할 필요가

있습니다만, 그점에 대해서도 향후 정리해보려고 합니다.

 

참고


  • [제2판]Python 기계학습 프로그래밍 달인 데이터 사이언스에 의한 이론과 실장 

      (https://www.amazon.co.jp/dp/B07BF5QZ41/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)

 

갱신내역


  • (2019/12/30) 중회귀 코드 예시를 추가

 


오역, 오타, 더 나은 표현은 댓글로 부탁합니다 '-'