愛林

[Python/Data] Load_diabetes 데이터셋을 이용한 회귀분석 실습 - 단순선형회귀분석 (Simple Regression Analysis) 본문

Data Science/DATA

[Python/Data] Load_diabetes 데이터셋을 이용한 회귀분석 실습 - 단순선형회귀분석 (Simple Regression Analysis)

愛林 2022. 7. 21. 00:29
반응형

 

 

회귀분석 가보자고 ..


 

회귀분석 (Regression Analysis) 실습

 

 

관련 패키지 import + 시각화 준비 (깨지지 않도록 폰트 지정)

 

import pandas as pd
import warnings
warnings.simplefilter(action = 'ignore', category = FutureWarning)
import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
import os

# 깨짐 방지를 위한 Font 지정
import os
if os.name =='nt' : 
    font_family = "Malgun Gothic"
else :
    font_family = "AppleGothic"

# 값이 깨지는 문제 해결을 위해 파라미터값 설정
sns.set(font=font_family, rc = {"axes.unicode_minus" : False})

 

 

우리가 사용할 데이터는

skcit learn 의 load_diabetes Data set. 당뇨병 진행도 예측 데이터이다.

 

from sklearn.datasets import load_diabetes

 

10종류의 독립변수, 독립변수의 값들은 모두 스케일링.

 

종속변수는 target 이다.

target : 1년 뒤 측정한 당뇨병의 진행률이다.

 

독립변수는 age(나이), sex(성별), bmi(비만도지수), bp(평균혈압), s1~s6(6종류의 혈액 검사 수치)

 

 

data = load_diabetes()
df = pd.DataFrame(data.data, columns = data.feature_names)
df['target'] = data.target
df.head()

 

data 에 diabetes 데이터를 저장했다.

 

age	sex	bmi	bp	s1	s2	s3	s4	s5	s6	target
0	0.038076	0.050680	0.061696	0.021872	-0.044223	-0.034821	-0.043401	-0.002592	0.019907	-0.017646	151.0
1	-0.001882	-0.044642	-0.051474	-0.026328	-0.008449	-0.019163	0.074412	-0.039493	-0.068332	-0.092204	75.0
2	0.085299	0.050680	0.044451	-0.005670	-0.045599	-0.034194	-0.032356	-0.002592	0.002861	-0.025930	141.0
3	-0.089063	-0.044642	-0.011595	-0.036656	0.012191	0.024991	-0.036038	0.034309	0.022688	-0.009362	206.0
4	0.005383	-0.044642	-0.036385	0.021872	0.003935	0.015596	0.008142	-0.002592	-0.031988	-0.046641	135.0

 

이제 이 친구들의 상관계수를 corr() 로 확인해본다.

 

절대값이 1에 가까울수록 상관도가 높은 것임을 기억하자.

 

 

눈에 띄는 상관계수로는 ... bmi 와 target (0.5864, 사실 그렇게 높은 값은 아닌 것 같은데) ,

s1과 s2 (0.896) 정도인 듯 하다.

데이터가 너무 많아서 눈이 침침해진다 ...

 

 

아무튼 간에 단순선형회귀분석을 진행해보자.

우리는 BMI 와 Target 으로 분석해볼 것이다.

 

 


 

단순선형회귀분석 실습

 

 

먼저 데이터의 정보를 탐색해보자.

 

df.info()

 

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 442 entries, 0 to 441
Data columns (total 11 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   age     442 non-null    float64
 1   sex     442 non-null    float64
 2   bmi     442 non-null    float64
 3   bp      442 non-null    float64
 4   s1      442 non-null    float64
 5   s2      442 non-null    float64
 6   s3      442 non-null    float64
 7   s4      442 non-null    float64
 8   s5      442 non-null    float64
 9   s6      442 non-null    float64
 10  target  442 non-null    float64
dtypes: float64(11)
memory usage: 38.1 KB

 

산점도도 같이 확인해보자.

 

sns.regplot('bmi', 'target', lowess = True, line_kws={'color' : 'red'}, data = df)
<AxesSubplot:xlabel='bmi', ylabel='target'>

 

seaborn 패키지의 regplot() 을 사용해서 추세선을 이용한 산점도를 확인해보았다.

lowess = True 는 국소회귀법을 사용해서 추세선을 그리게 된다.

 

 

이상값을 확인해보자.

 

## 이상값 확인
fig , (ax1, ax2) = plt.subplots(1,2)

sns.boxplot('bmi', data = df, ax=ax1)
ax1.set_title('bmi')

# dist 의 상자 그림을 두 번째로 그린다
sns.boxplot('target', data=df, ax=ax2)
ax2.set_title('rate')
Text(0.5, 1.0, 'rate')

bmi 데이터 쪽에 이상값이 보인다.

 

 

분포를 시각화해보자.

 

## 분포 시각화
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (10,4))

sns.kdeplot(df['bmi'], ax=ax1)
ax1.set_title('bmi')

sns.kdeplot(df['target'], ax=ax2)
ax2.set_title('rate')
Text(0.5, 1.0, 'rate')

 

kdeplot을 이용했다. 밀도plot 을 만드는 seaborn 패키지 함수이다.

bmi 와 rate 를 밀도함수로 만들어주었다.

 

거의 정규분포 비스무리한 것을 확인할 수 있다. (조금 이상하긴 하지만.)

 

 

이번에는 비대칭을 확인해보자.

비대칭은 왜도 (Skewness) 로 확인한다.

 

# 비대칭 확인 (왜도)
import scipy.stats

print(scipy.stats.skew(df['bmi']))
print(scipy.stats.skew(df['target']))
0.5961166556214368
0.43906639932477265

 

scipy.stats 의 skew() 를 사용해서 왜도를 살펴보았다.

 

왜도 > 0 이므로 살짝 왼쪽으로 치우친 것을 볼 수 있다.

근데 아주 살짝 치우친 것이므로 크게 개의치 않아도 되지 싶다.

 

 


 

sklearn 의 LinearRegression 을 사용해서 회귀분석을 진행해보자.

 

from sklearn.linear_model import LinearRegression
# 데이터셋 생성
X = df.bmi.values
y = df.target.values

l_train_X1 = X.reshape(-1,1)
l_test_y1 = y.reshape(-1,1)

print(X.shape)
print(l_train_X1.shape) #  형태를 바꾸어주었다.

데이터를 준비했다.

 

이제 모델에  데이터를 피팅시켜서 모델을 학습시켜보자.

 

## 모델 학습
lr_model = LinearRegression()
lr_model.fit(l_train_X1, l_test_y1)

 

회귀계수 (Coefficient) 를 확인해보자.

이전에, 회귀계수는 Y절편과, 기울기였다. (B0, B1)

 

print(lr_model.coef_[0]) # 기울기값
print(lr_model.intercept_) # y절편
[949.43526038]
[152.13348416]

 

coef_[0] 는 기울기값,

intercept_ 는 y절편값이다.

 

이걸 바탕으로 해서 선형회귀 모델로 값을 예측해본다.

 

lr_model.predict([[-2], [-1], [0], [1], [2]])
array([[-1746.73703661],
       [ -797.30177622],
       [  152.13348416],
       [ 1101.56874455],
       [ 2051.00400493]])

맞는 지 확인해보자.

 

lr_model.coef_[0] * -2 + lr_model.intercept_
array([-1746.73703661])

위랑 똑같은 결과가 나왔다.

잘 학습된 것 같다.

 

 

이제 잔차를 계산해보자.

 

lr_prediction = lr_model.predict(l_train_X1) # lr_prediction 값
lr_residuals = l_test_y1 - lr_prediction    # 잔차

 

잔차는 우리가 test값 - 예상한 값 prediction 값 (선형모델값) 이다.

prediction 값은 X1 train 값을 선형모델에 넣어서 돌린 y값이다.

 

아무튼간에 식을 작성해주었다.

 

다음은 R^2. R-squared . 결정계수를 계산해준다.

결정계수는 선형모델에서 아주아주 중요한 값이었다.

 

전체 분산값 중에 선형모델이 설명하는 값의 비율이었다.

 

이 결정계수의 값이 0.65 이상이어야 유효했고,

SST - SSR / SST 식을 가지고 있었다.

 

SST(전체 분산값, 총제곱합), SSR(선형모델이 설명하는 값, 회귀제곱합)

 

1 - SSE / SST 또한 결정계수의 값이다.

 

 

# R_squared 계산
SSE = (lr_residuals **2).sum() # 잔차의 제곱합.
SST = ((l_test_y1 - l_test_y1.mean())**2).sum()  # 총변동 혹은 총제곱합
R_squared = 1 - (SSE/SST)
print('R_squared : ', R_squared)

 

SSE 는 잔차의 제곱합이므로,

아까 위에서 구한 lr_residuals 를 제곱한 값을 모두 sum() 한다.

 

SST 는 총 제곱합이므로, 데이터 값에서 평균을 빼준 것을 제곱해준다. 그리고 이것도 sum() 해준다.

 

결정계수는 1- (SSE/SST) 이다.

 

R_squared :  0.3439237602253802

 

결정계수가 0.65를 넘지 않으므로, 유효하지 않은 결정계수값이다.

 

그러므로 BMI 는 Target 을 설명할 수 없다.

 

 

그럼 이 모델을 시각화해보자.

 

sns.regplot(l_train_X1, l_test_y1, lowess=True, line_kws = {'color' : 'red'}, data= df)
plt.title('y = {}*x + {}'.format(lr_model.coef_[0], lr_model.intercept_))
plt.show()

회귀분석 모델 X_Train, y_test 산점도
위에서 했던 bmi & Target 산점도

 

아까 처음에 bmi 랑 Target 이랑 했던 산점도랑 똑같이 나왔다. 당연함. 같은 데이터임..

 

 


 

단순선형회귀 통계적 분석

 

그럼 이제 단순선형회귀를 통계적으로 분석해보자.

 

 

OLS 를 사용해보자,

OLS 는 최소자승법(최소제곱법) 이다. 잔차제곱합을 최소화하는 방법이었다.

 

OLS 를 불러와주자.

 

from statsmodels.formula.api import ols

 

종속변수는 Target, 독립변수는 bmi 를 피팅시켜주자.

 

res_sr = ols('target ~ bmi', data = df).fit() # 종속변수  = target, 독립변수 = bmi

 

결과를 확인해보자.

 

summary() 를 사용하면 결과를 확인할 수 있다.

 

res_sr.summary()

 

 

 

[ 해석 ]

 

R-squared 결정계수도 0.344 (아까 구한 거랑 같음)

1에 가까울 수록 좋다.

 

coef 는 회귀계수 Coefficient 이다.

[949.43526038]
[152.13348416]

 

위에서 구한 기울기값은 949, Y절편값이 152였다.

Intercept 가 Y절편값이고, bmi 가 기울기값이다. 

 

Target = bmi * 949 + 152 

 

회귀식인 것이다.

 

No.observations 는 442. 그러니까 442개의 표본수를 가지고 분석을 했다는 말이다.

Df Residuals 는 잔차의 자유도이다.

(잔차의 자유도 : 표본 수 - 종속변수 개수 - 독립변수 개수)

 

Prob(F-staatistic) 이3.47e -42 로,

0.05보다 작은 값이 나왔다. (유의확률)

유의미하다는 뜻이다. 

 

P>|t| 는 독립변수의 유의확률인데 0.025로 0.05보다 작으므로 유의미하다.

 

 

 

결과 요약

 

target 에대하여 bmi 로 예측하는 회귀분석을 실시한 결과,

이 회귀모델은 통계적으로 유의미했다. 

F(1,440) = 230.7, p<0.05

 

bmi 독립변수의 회귀계수는 949.4353으로, target 에 대하여 유의미한 예측 변인인 것으로 나타났다.

 

Comments