[분류] 심부전증 데이터 분석 & 예측 모델

2023. 11. 19. 21:18ML&DL/Data Analysis

 

-  목표: 심부전증 데이터 분석 및 예측 모델 만들기 

-  데이터셋 

https://www.kaggle.com/andrewmvd/heart-failure-clinical-data

 

Heart Failure Prediction

12 clinical features por predicting death events.

www.kaggle.com

- 데이터 변수

age: 환자의 나이
anaemia: 환자의 빈혈증 여부 (0: 정상, 1: 빈혈)
creatinine_phosphokinase: 크레아틴키나제 검사 결과
diabetes: 당뇨병 여부 (0: 정상, 1: 당뇨)
ejection_fraction: 박출계수 (%)
high_blood_pressure: 고혈압 여부 (0: 정상, 1: 고혈압)
platelets: 혈소판 수 (kiloplatelets/mL)
serum_creatinine: 혈중 크레아틴 레벨 (mg/dL)
serum_sodium: 혈중 나트륨 레벨 (mEq/L)
sex: 성별 (0: 여성, 1: 남성)
smoking: 흡연 여부 (0: 비흡연, 1: 흡연)
time: 관찰 기간 (일)
DEATH_EVENT: 사망 여부 (0: 생존, 1: 사망)

 

 

 

💻 실습

라이브러리 import

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

 

데이터 불러오기 & 확인

df = pd.read_csv('heart_failure_clinical_records_dataset.csv')
df

df.info()

age: 환자의 나이 (수치형)
anaemia: 환자의 빈혈증 여부 (0: 정상, 1: 빈혈) (범주형)
creatinine_phosphokinase: 크레아틴키나제 검사 결과 (수치형)
diabetes: 당뇨병 여부 (0: 정상, 1: 당뇨) (범주형)
ejection_fraction: 박출계수 (%) (수치형)
high_blood_pressure: 고혈압 여부 (0: 정상, 1: 고혈압) (범주형)
platelets: 혈소판 수 (kiloplatelets/mL) (수치형)
serum_creatinine: 혈중 크레아틴 레벨 (mg/dL) (수치형)
serum_sodium: 혈중 나트륨 레벨 (mEq/L) (수치형)
sex: 성별 (0: 여성, 1: 남성) (범주형)
smoking: 흡연 여부 (0: 비흡연, 1: 흡연) (범주형)
time: 관찰 기간 (일) (수치형)
DEATH_EVENT: 사망 여부 (0: 생존, 1: 사망) (범주형)

 

* 기초통계량

df.describe()

 

 

* 데이터 시각화 (histplot, joinplot, pairplot)

 

- age 와 DEATH_EVENT (사망 여부 (0: 생존, 1: 사망))

sns.histplot(x='age', data=df, hue='DEATH_EVENT', kde=True)

=> 80대가 넘어가면 생존률 보다 사망률이 높음

 

- 크레아틴키나제 3000 보다 작은 값만 보기 

sns.histplot(data=df.loc[df['creatinine_phosphokinase'] < 3000, 'creatinine_phosphokinase'])

- 박출 계수와 사망 여부 

sns.histplot(x='ejection_fraction', data=df, bins=13, hue='DEATH_EVENT', kde=True)

 

sns.boxplot(x='DEATH_EVENT', y='ejection_fraction', data=df)

=> 낮을 수록 사망률이 높은 경향을 보임

 

- 혈소판 수와 사망 여부

sns.histplot(x='platelets', data=df, hue='DEATH_EVENT')

 

 

 

sns.jointplot(x='platelets', y='creatinine_phosphokinase', hue='DEATH_EVENT', data=df, alpha=0.3)

 

=> 이상치가 보임 

 

 

- 관찰기간(일)과 사망 여부

sns.histplot(x='time', data=df, hue='DEATH_EVENT', kde=True)

 

 

sns.boxplot(x='DEATH_EVENT', y='time', data=df)

 

=> 관찰 기간이 짧으면 사망률이 높고, 오히려 관찰 기간이 길면 생존률이 높다

=> 관찰 기간이 짧으면 심부전증이 악화된 환자일 확률이 높겠다. 반대로 관찰기간이 긴 환자일 수록 심부전증을 초기 발견해서 치료하고 있겠다는 개인적인 생각

 

* 데이터 전처리

from sklearn.preprocessing import StandardScaler

 

- 수치형(X_num), 범주형(X_cat), 타겟 데이터(y) 구분

X_num = df[['age', 'creatinine_phosphokinase','ejection_fraction', 'platelets','serum_creatinine', 'serum_sodium']]
X_cat = df[['anaemia', 'diabetes', 'high_blood_pressure', 'sex', 'smoking']]
y = df['DEATH_EVENT']

 

- 스케일러

- 수치화 데이터를 평균이 0이고 분산이 1 값으로 표준화해줌

scaler = StandardScaler()
scaler.fit(X_num)
X_scaled = scaler.transform(X_num)
X_scaled = pd.DataFrame(data=X_scaled, index=X_num.index, columns=X_num.columns)
X = pd.concat([X_scaled, X_cat], axis=1)
X.head()

 

 

* train/test 데이터 7:3으로 분리

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)

 

* 모델 학습

-LogisticRegression

from sklearn.linear_model import LogisticRegression
model_lr = LogisticRegression(max_iter=1000)
model_lr.fit(X_train, y_train)

 

- 결과 평가

from sklearn.metrics import classification_report

pred = model_lr.predict(X_test)
print(classification_report(y_test, pred))

 

- XGBoost

from xgboost import XGBClassifier

model_xgb = XGBClassifier()
model_xgb.fit(X_train, y_train)
pred = model_xgb.predict(X_test)
print(classification_report(y_test, pred))

 

 

 

- RandomForest

from sklearn.ensemble import RandomForestClassifier

model_rf = RandomForestClassifier()
model_rf.fit(X_train, y_train)
pred = model_rf.predict(X_test)
print(classification_report(y_test, pred))

 

- 특징 중요도 확인

plt.bar(X.columns, model_xgb.feature_importances_)
plt.xticks(rotation=90)
plt.show()