티스토리 뷰

반응형

기본적으로 의료데이터의 분석을 위한 기초 내용은 아래의 url을 참고해서 보고오자.

 

 

2021.04.28 - [데이터분석] - 의료데이터 분석하기 입문

 

 

 

 

kaggle 데이터를 분석해보자. 아래의 심부전증 데이터를 가져오자.

 

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

 

Heart Failure Prediction

12 clinical features por predicting death events.

www.kaggle.com

 

 

1. 데이터셋 준비하기

데이터를 받아서 아래와 같은 코드를 통해 csv파일을 불러오자

 

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

 

  • 컬럼내용 정리
  • 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: 사망)

 

2. EDA 분석

우선은 head() 사용해서 값들을 보자.

 

특이점을 보면, age는 integer로 표현은 되어 있는데 flout로 되어 있는것을 알 수 있다. 그리고 0, 1로만 이루어진 값들은 컬럼의 유무만 나타낸 것임을 알 수있다. 무슨 내용인지 쓰윽 확인만 해놓자.

 

 

 

info() 를 통해 알 수 있는 것은, 데이터 타입, Non-Null count를 통해 비어있는 것이 없다는 것을 알 수 있다. 대부분 int이지만, 몇몇개는 float인것은 알 수 있다. 생각보다 클린한 셋인 것을 알 수 있다.

 

 

describe()를 통해 알 수 있는 것은 갯수, 평균, 최소값, 하위25프로값, 중간값, 상위25프로값, 최대값을 볼수 있다. 우선 0과 1로 이루어진 데이터들을 확인해야한다. smoking의 평균을 보면 0.3정도로 비흡연자가 많다는 것을 알 수 있다. 비흡연자가 많긴하지만, 언벨런스한 데이터는 아니기 때문에 사용해도 무방하다. 그리고 과도하게 큰값이나 작은 값이 있는지를 확인하자. creatinine_phosphokinase를 보면 max값이 7861로 상당히 큰편이므로 outlier로 배제를 할 필요가 있다.

 

 

 

수치가 아닌 시각적으로 판단해 보기

위의 그래프는 구하고자 하는 값이 DEATH_EVENT이다. 따라서 결과 값에 따른 age를 확인한 것이다. 주의 할 점은 age가 겹쳐있는 것이 아니라는 것이다.

 

 

 

 

 

creatinine_phosphokinase는 위에서 추치로 본 것과 같이 outlier가 많은 것을 알 수 있다. 따라서 범위를 제한해서 표현한 것이다.

 

 

 

 

위의 그래프는 종속변수(DEATH_EVENT)값과 ejection_fraction을 비교한 값이다. 핵심은, 정확성은 유용하지만, recall을 높이는데 크게 도움이 안될 것 같다는 생각이 든다.

 

 

 

 

 

혈소판 수치의 경우, 정규분포를 그리니 통계적으로는 적정해 보인다. 하지만, death_event와 상관이 없어보인다. 따라서 학습에 크게 도움이 안될 것으로 보인다.

 

 

 

 

boxplot으로 확인을 해보면, outlier를 쉽게 확인가능한 것을 알 수 있다.

 

 

결과적으로는 시각적으로는 크게 인사이트를 얻기가 힘들다는 것을 알 수 있다.

 

 

 

 

3. 전처리하기

연구용 데이터라 그런지, 대부분 클린한 상태이다. 그리고 0과 1로 원핫벡터도 잘 되어있는 것을 확인 할 수 있다. 따라서 원핫벡터로 되어있는 것을 제외한 수치형 데이터를 standardScaler를 활용해서 평균을 0으로 std는 1로 바꿔주는 작업만 해주면 될 것 같다.

 

from sklearn.preprocessing import StandardScaler
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']
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_num에는  scaling을 할 값을 넣어주고, X_cat에는 스케일링이 필요없는 값들을 넣어준다. 그리고 그케일링을 진행한 후에 값들을 합해준다. 결과는 아래와 같이 나온다.

 

 

 

 

4. 데이터 분리

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)

 

train set과 test set으로 나눠준다.

 

 

 

5. 모델 학습 및 결과 평가

from sklearn.linear_model import LogisticRegression
model_lr = LogisticRegression(max_iter=1000)
model_lr.fit(X_train, y_train)
'''
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                   intercept_scaling=1, l1_ratio=None, max_iter=1000,
                   multi_class='auto', n_jobs=None, penalty='l2',
                   random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
                   warm_start=False)
'''

 

모델을 LogisticRegression으로 모델을 만들고 fit으로 학습을 한다. 만약 이터래이션이 부족해서 학습이 되지 않았다고 뜬다면, max_iter이 몇인지 찾아서 보통은 디폴트가 100임. 그리고 늘려가면서 학습을 해주면 된다. verbose를 넣어주면 학습하는 과정을 보여준다.( ex_ model_lr = LogisticRegression(max_iter=1000, verbose=1)  ) 2를 넣으면 더 많이 보여 주고 3을 넣으면 시간도 보여준다.

 

from sklearn.metrics import classification_report
pred = model_lr.predict(X_test)
print(classification_report(y_test, pred))

'''
              precision    recall  f1-score   support

           0       0.78      0.92      0.84        64
           1       0.64      0.35      0.45        26

    accuracy                           0.76        90
   macro avg       0.71      0.63      0.65        90
weighted avg       0.74      0.76      0.73        90


accuracy 0.76 90
'''

 

 

90의 데이터로 평가한 것이 76%의 정확도를 가진다는 것을 알 수 있다.

 

 

xgboost 사용하기

 

from xgboost import XGBClassifier
model_xgb = XGBClassifier()
model_xgb.fit(X_train, y_train)
'''
XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
              colsample_bynode=1, colsample_bytree=1, gamma=0,
              learning_rate=0.1, max_delta_step=0, max_depth=3,
              min_child_weight=1, missing=None, n_estimators=100, n_jobs=1,
              nthread=None, objective='binary:logistic', random_state=0,
              reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None,
              silent=None, subsample=1, verbosity=1)
'''

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

'''
              precision    recall  f1-score   support

           0       0.84      0.89      0.86        64
           1       0.68      0.58      0.62        26

    accuracy                           0.80        90
   macro avg       0.76      0.73      0.74        90
weighted avg       0.79      0.80      0.79        90

'''

 

정확도가 80정도 나오는데, 분류 데이터에서는 나쁘지 않은 값이다.

 

 

 

위의 그래프는 중요도를 나타내는 그래프이다.

 

 

 

6. Precision-Recall 확인하기

precision과 recall의 관계를 확인해 보자.

from sklearn.metrics import plot_precision_recall_curve
fig = plt.figure()  # figure하나를 만들어 주자.
ax = fig.gca()  # gca를 사용해서 ax를 사용할 수 있다.
plot_precision_recall_curve(model_lr, X_test, y_test, ax=ax)
plot_precision_recall_curve(model_xgb, X_test, y_test, ax=ax)

 

 

 

 

Recall을 증가시키면서 Precision이 어떻게 나오는지를 확인하는 것이다. 그림에 보면 AP라는게 있다. Precision이 AP값이 높을 수록 Recall을 증가시키면서 잘 유지했다는걸 의미한다. 따라서 AP가 1에 가까울 수록 좋은거다. 위 그림을 보면 XGBClassifier가 일반적으로 로지스틱회귀보다 위쪽에 있는것을 보면, XGB분류가 일반적으로 좋은 성능을 만들고 있다는 것을 알 수 있다.

 

 

 

7. ROC 커프 활용하기

from sklearn.metrics import plot_roc_curve
fig = plt.figure()
ax = fig.gca()
plot_roc_curve(model_lr, X_test, y_test, ax=ax)
plot_roc_curve(model_xgb, X_test, y_test, ax=ax)

 

 

 

위 그림을 보면 x축과 y축에 True Positive Rate와 False Positive Rate 2가지가 나오는 것을 알 수 있다. 우리의 목적은 False Positive Rate를 낮게 유지하고 싶은 것이다.따라서 False Positive Rate가 빨리 증가하면서 빨리 1에 가까워지는 것을 보고 싶은거다. 따라서 위쪽에있는게 더 좋은거다. 이 경우는 로지스틱 회기가 더 좋은 걸로 나온다.

 

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함