본문 바로가기
머신러닝 with Python

[머신러닝 with Python] 선형회귀(Linear Regression) / 당뇨병(Diabetes) 데이터 활용 / EDA 시각화 포함

by CodeCrafter 2023. 9. 19.
반응형

 이번에는 지난 포스팅에 이어서 선형회귀(Linear Regression)에 대해서 알아보겠습니다.

 

 지난 포스팅에서는 선형회귀의 기본 개념과 예제 데이터를 만들어 파이썬 코딩을 통해, 모델을 구현해보고 이를 시각화 해보았는데요

[머신러닝 with Python] 선형회귀(Linear Regression) / 최소제곱법(Least Square Methods) (1)

 

 

 이번에는 실제 데이터를 활용해서 선형회귀를 구현해보겠습니다. 

 

 분석에 사용될 데이터는 당뇨병(Diabetes) 데이터 이며, 시각화를 위해 단순선형회귀로부터 시작하고 다중 선형회귀로 주어진 데이터를 최대한 활용하여 선형회귀 모델을 만들어 보겠습니다.

 

1. 당뇨병 데이터(Diabetes) 알아보기

- 해당 데이터의 링크 : https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_diabetes.html

 

sklearn.datasets.load_diabetes

Examples using sklearn.datasets.load_diabetes: Release Highlights for scikit-learn 1.2 Gradient Boosting regression Plot individual and voting regression predictions Model Complexity Influence Mode...

scikit-learn.org

 

- DIABETE 데이터셋은 피스탈로지스틱(Pisztaloczi) 교수와 함께 작업한 Dr. Bradley Efron에 의해 수집되었습니다.

- 이 데이터셋은 당뇨병 환자의 의학적인 측정값과 당뇨병 진행 정도를 기록한 것으로, 주로 통계 및 머신러닝 연구에서 사용되며, 위 링크에서 말해주듯 사이킷런(Scikit Learn) 패키지를 통해 쉽게 불러올 수 있는 데이터 입니다.

 

- 간략한 데이터 설명 

 * 수집 시기: 이 데이터셋은 1980년대에 수집되었습니다.
 * 수집 방법: 데이터는 당뇨병 환자들로부터 의학적인 측정값을 수집함으로써 얻어졌습니다. 이러한 측정값은 환자의 나이, 성별, BMI(체질량 지수), 혈압 및 여러 혈청 검사 결과를 포함하고 있습니다.
 * 데이터 활용: 이 데이터셋은 당뇨병 연구 및 통계 분석, 머신러닝 모델의 성능 평가, 회귀 분석 등 다양한 분야에서 활용됩니다. 주요 목적은 당뇨병 환자의 진행 정도를 예측하는 모델을 개발하고 테스트하는 것입니다.
* 데이터 특징: 데이터셋에는 총 442명의 환자 정보가 포함되며, 각 환자는 10개의 특성(독립 변수)과 당뇨병 진행 정도(종속 변수)가 기록되어 있습니다. 이 데이터는 보다 기술적이고 통계적인 목적으로 사용되며, 당뇨병 예측 및 관련 연구 분야에서 많이 활용됩니다.
* 출처: 이 데이터셋은 scikit-learn 라이브러리와 함께 제공되며, 머신러닝 및 데이터 분석 연구를 위한 예제 데이터 중 하나로 사용됩니다.

 

 

2. EDA를 통한 당뇨병 데이터 알아보기

 * EDA란? EDA는 Exploratory Data Analysis의 약자로 탐색적 데이터 분석이라고 불립니다. 이는 데이터를 탐색하고 이해하는 과정을 말하며, 데이터의 구조, 패턴, 이상치,주요 변수 등을 파악하는데 사용됩니다. 

 

 

1) 데이터 불러오기 및 데이터 기본 정보 확인

* 데이터 처리를 위한 numpy와 pandas / 시각화를 위한 pyplot과 seaborn / 데이터를 불러오기 위한 사이킷런의 datasets의 load_diabets를 임포트해줍니다.

* 이후 데이터를 불러오고 data로 저장해준 뒤 데이터의 정보를 확인해보겠습니다.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_diabetes

# DIABETES 데이터 불러오기
diabetes = load_diabetes()
data = pd.DataFrame(data=np.c_[diabetes.data, diabetes.target], columns=diabetes.feature_names + ['target'])

# 1. 데이터셋 기본 정보 확인 - 데이터의 일부 확인
data.head()

 

# 1. 데이터셋 기본 정보 확인 - 전체적인 정보 확인
data.info()

* 데이터는 총 10개의 변수(Variables / Features)로 구성되어 있으며 1개의 target으로 구성되어 있습니다.

* 이때 target은 당뇨병의 진행정도를 뜻하며, 당뇨병의 진행 정도가 측정된 당뇨 환자들의 혈압 / 혈청 호모글로빈 A1c 등 여러 특성을 기바능로 계산된 값을 의미합니다. 이는 값이 높을수록 당뇨병 진행이 심함을 의미합니다.

* 총 데이터의 개수는 442개이며 모든 변수들이 결측치가 없습니다.(non-null)

* 또한 모든 데이터들의 타입이 실수형(float64)으로 구성되어 있습니다.

 

 

2) 데이터 시각화

 

* 다음은 각 변수들을 히스토그램으로 시각화해보겠습니다.

# 2. 데이터 시각화
# 히스토그램
data.hist(bins=20, figsize=(12, 6))
plt.tight_layout()
plt.show()

* 범주형인 sex, 그리고 s4, target을 제외하고는 정규분포의 모습을 보이는 것 같습니다.

 

 

* 다음은 Box plot으로 해당 데이터의 분포를 표현해보았습니다.

# Box plot
sns.boxplot(data=data.iloc[:, :-1], orient="v")
plt.title("Box plot by each features")
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

* 더 직관적으로 다가오는 것 같습니다. Box plot의 경우

 1) 박스 범위 내 : 1사분위수(Q1)과 3사분위수(Q3)를 표현

 2) 가로선 : 중앙값(Media)

 3) 상단 및 하단 가로선 : 이상치(Outlier)의 경계를 의미합니다. 이상치의 경계는 IQR를 활용하는데요

  ** IQR은 Inter Qunatile Range의 약어로 1분위 수와 3분위수의 차이를 의미합니다. 해당 값에 1.5를 곱해서 각 1분위수에서는 빼주고, 3분위 수에서는 더해주는 것으로 이상치 경계의 상한과 하한을 정의합니다.

   a) 데이터의 1사분위수(Q1)와 3사분위수(Q3)를 계산
   b) IQR을 계산 ( IQR = Q3 - Q1 )

   c) 이상치(Outlier)의 경계를 정의 : 이상치 경계 상한 = Q3 + 1.5 * IQR / 이상치 경계 하한 = Q1 - 1.5 * IQR
   d) 이상치 경계를 벗어나는(초과 또는 미달하는) 값을 이상치로 정의

 

 

* 다음은 페어플롯(Pair Plot)을 일부 그려보겠습니다.

# 페어 플롯
sns.pairplot(data=data.iloc[:, :4], height=2)
plt.tight_layout()
plt.show()

 * 이를 통해 각 변수들의 상관관계를 직관적으로 알 수 있습니다. 단, 모든 변수들을 다 그리기에는 시간상 제한과 시각적으로도 직관적으로 다가오지 않기에 일부만을 시각화해보았습니다.

 

* 이를 보완하기 위해 특성(Features)간의 상관관계를 시각화 해보겠습니다.

# 3. 특성 간 상관 관계 시각화
corr_matrix = data.corr()
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', linewidths=0.5)
plt.title("Heatmap of Correlation between each features")
plt.show()

* 여기서 사용된 수치는 두 변수 간의 피어슨 상관계수를 의미합니다. 이를 수식으로 표현하면 아래와 같습니다.

* 이를 활용하면 변수간의 선형적인 관계를 이해할 수 있으며, 중요한 변수를 선택하거나 다중공선성을 평가하는데 도움이 됩니다. 

 

 

* 이 중 BMI와 당뇨병 진행 정도를 산점도(Scatter plot)으로 시각화해보겠습니다.

# 4. 종속 변수와 독립 변수 간 관계 시각화
sns.scatterplot(x='bmi', y='target', data=data)
plt.xlabel("BMI")
plt.ylabel("Progression of Diabetes")
plt.title("Relationship between Progression of Diabetes & BMI")
plt.show()

 

3. 선형회귀를 활용한 당뇨 진행정도 예측

이번에는 선형회귀를 활용해 당뇨 진행정도(Target)을 예측해보겠습니다. 

 

*먼저 단순선형회귀를 통해 시각화 해보겠습니다. 이때 변수는 BMI로 해보겠습니다.

* EDA에서 활용한 패키지를 유사하게 활용하며 이때 선형회귀를 위해 Sciket Learn의 linear_modle의 LinearRegression을 이용했습니다. 

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_diabetes
from sklearn.linear_model import LinearRegression

# Diabetes(당뇨병) 데이터셋 로드
diabetes = load_diabetes()
X = diabetes.data[:, 2]  # 3번째 특성인 BMI를 사용 (독립 변수)
y = diabetes.target       # 당뇨병 진행 정도 (종속 변수)

# 단순선형회귀 모델 선택 및 훈련
model = LinearRegression()
X = X.reshape(-1, 1)  # 1차원 배열을 2차원 배열로 변환
model.fit(X, y)

# 모델 파라미터 출력
print("Slope(Beta):", model.coef_[0])
print("Intercept:", model.intercept_)

* 도출된 결과는, a) 기울기 : 949.435....  , b) target의 절편 : 151.133.......   입니다. 

 

 

*위 결과를 시각화해보면 아래와 같습니다.

# 시각화
plt.scatter(X, y, alpha=0.5)
plt.plot(X, model.predict(X), color='red', linewidth=2)
plt.xlabel("BMI")
plt.ylabel("progression of diabetes")
plt.title("The example of Linear Regression")
plt.show()

* 이를 통해 target과 BMI의 관계를 파악해볼 수 있었습니다. 이제 에측을 한번 해보겠습니다.

 

 

 

- 이번에는 다중 선형회귀모델을 활용해 데이터의 모든 변수들을 사용해 당뇨병의 진행정도(target)을 예측해보겠습니다.

* 이때, 해당 데이터를 학습용(train)과 테스트(test)용으로 나누어 사용하며, 테스트 모델의 성능 평가를 위해 평균제곱오차인 MSE와  결정 계수인 R-squared를 사용해보겠습니다.

 

 

*먼저 필요 라이브러리 임포트 / 데이터 로드 / 데이터를 train과 test용으로 나누었습니다.

import numpy as np
import pandas as pd
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score

# DIABETES 데이터 불러오기
diabetes = load_diabetes()
X = diabetes.data  # 독립 변수
y = diabetes.target  # 종속 변수

# 데이터를 훈련 세트와 테스트 세트로 나눔
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

 

*train 데이터로 선형회귀 모델을 학습시키고 도출된 식은 아래와 같습니다.

# 다중 선형 회귀 모델 생성 및 훈련
model = LinearRegression()
model.fit(X_train, y_train)

# 회귀식 계수 (coef_)와 절편 (intercept_) 추출
coef = model.coef_
intercept = model.intercept_

# 변수 이름 가져오기 (age, sex, bmi, bp, s1, s2, s3, s4, s5, s6)
feature_names = diabetes.feature_names

# 회귀식 구성 요소 출력
equation = f"다중 선형 회귀식: target = {intercept:.2f} "
for i, feature_name in enumerate(feature_names):
    equation += f"+ ({coef[i]:.2f} * {feature_name}) "

print(equation)

 

* 이제 test 데이터로 모델을 평가해보겠습니다. 

# 테스트 데이터로 예측
y_pred = model.predict(X_test)

# 모델의 성능 지표 계산
mse = mean_squared_error(y_test, y_pred)  # 평균 제곱 오차(MSE)
r2 = r2_score(y_test, y_pred)  # 결정 계수 (R-squared)

print("평균 제곱 오차 (MSE):", mse)
print("결정 계수 (R-squared):", r2)

* 결과는 위와 같이 도출됩니다.

 

 

 

 

* 더 직관적인 해석을 위해 도출된 회귀식을 활용해   (feature vs target)의 그래프를 각 feature 별로 그려보았습니다.

 (코딩이 길어지다보니 오류가 생길 수 있어 라이브러리와 train/test split 등을 포함해 코딩 전체를 포함시킵니다)

 

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

# DIABETES 데이터 불러오기
diabetes = load_diabetes()
X = diabetes.data  # 독립 변수
y = diabetes.target  # 종속 변수

# 데이터를 훈련 세트와 테스트 세트로 나눔
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 다중 선형 회귀 모델 생성 및 훈련
model = LinearRegression()
model.fit(X_train, y_train)

# 변수 이름 가져오기 (age, sex, bmi, bp, s1, s2, s3, s4, s5, s6)
feature_names = diabetes.feature_names

# 변수와 target 간의 관계 시각화
plt.figure(figsize=(16, 12))

for i, feature_name in enumerate(feature_names):
    plt.subplot(3, 4, i + 1)
    plt.scatter(X_train[:, i], y_train, label="Data point")
    plt.xlabel(feature_name)
    plt.ylabel("target")
    plt.title(f"{feature_name} vs. target")
   
    # 다중 선형 회귀식을 포함한 선 그리기
    x_range = np.linspace(min(X_train[:, i]), max(X_train[:, i]), 100)
    y_pred = model.predict(X_train)
    plt.plot(x_range, model.coef_[i] * x_range + model.intercept_, color='red', linewidth=3, label="Linear Model(Multiple)")
   
    plt.legend()

plt.tight_layout()
plt.show()

 

 

위 그림에서 파란색은 데이터 포인트를 의미하고 빨간선은 회귀선을 의미합니다. 

 

이때 회귀선은 위에서 도출한 다중회귀식에서, 다른 변수들은 0으로 처리하고 해당 변수에 데이터를 포함한 그래프로 인식하면 됩니다. 

 

Ex) target vs age 의 경우, target = 151.35 -241.96 * age  의 식을 그린 것입니다.

반응형

댓글