본문 바로가기

파이썬/머신러닝

캐글 heart 데이터로 EDA부터 로지스틱회귀, 트리모델 적합까지 총정리

오늘도 열심히 Kaggle 필사!

오늘은 심장질환을 예측하는 heart.csv 파일로 linear classifiers와 tree model을 학습시켜봤다.

 

heart.csv
0.01MB

 

output이 타겟(y), 나머지는 X변수이다.

 

 

데이터 구조 파악

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

heart = pd.read_csv('heart.csv')
heart.head()

 

 

print(heart.shape())
>>(303,14)
print(heart.info())

총 303개의 행, 14개의 열로 이루어져있고 각 컬럼별 속성을 확인해보면 null 값은 없고 oldpeak 컬럼을 제외하면 나머지는 모두 int 타입이다.

 

#categorical 변수와 continuous 변수 구분

cat_col = ['sex', 'exng' ,'caa','cp','fbs','restecg','slp','thall']
con_cols = ["age","trtbps","chol","thalachh","oldpeak"]
target_col = ["output"]

#describe() : 다양한 통계량 요약 함수, df의 경우 각 열의 요약값을 보여줌
#transpose() : 행열 전환 함수
heart[con_cols].describecribe().transpose()

변수를 카테고리형 변수와 연속형 변수로 나누어서 연속형 변수의 mean, std, min, max 등을 확인해본다.

 

con_target = ["age","trtbps","chol","thalachh","oldpeak", "output"]
heart_corr = heart[con_target].corr().transpose()
heart_corr

연속형 변수와 타겟값인 output과의 상관관계를 살펴보면 thalachh(Maximum heart rate achieved)변수가 심장질환 유발에 가장 큰 영향을 미치는 것으로 보인다.

 

cat_target = ['sex', 'exng' ,'caa','cp','fbs','restecg','slp','thall', 'output']
heart_corr2 = heart[cat_target].corr().transpose()
heart_corr2

 

다음으로 카테고리형 변수들과 output과의 상관관계를 보면 cp(Chest pain type)과 slp(Slope)이 심장질환 유발에 가장 큰 영향을 미친다.

 

columns = ['sex', 'exng' ,'caa','cp','fbs','restecg','slp','thall', "output"]

for col in columns:
    print(heart[col].value_counts())
    
>>>
1    207
0     96
Name: sex, dtype: int64
0    204
1     99
Name: exng, dtype: int64
0    175
1     65
2     38
3     20
4      5
Name: caa, dtype: int64
0    143
2     87
1     50
3     23
Name: cp, dtype: int64
0    258
1     45
Name: fbs, dtype: int64
1    152
0    147
2      4
Name: restecg, dtype: int64
2    142
1    140
0     21
Name: slp, dtype: int64
2    166
3    117
1     18
0      2
Name: thall, dtype: int64
1    165
0    138
Name: output, dtype: int64

 

참고로 카테고리형 변수들을 갖고 value_counts 함수를 쓰면 각 컬럼의 속성값 별로 데이터가 몇개씩 있는지 확인할 수 있다.

 

 

전처리

# Scaling
from sklearn.preprocessing import RobustScaler

# Train Test Split
from sklearn.model_selection import train_test_split

# Models
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import GradientBoostingClassifier

# Metrics
from sklearn.metrics import accuracy_score, classification_report, roc_curve

# Cross Validation
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV

#원본 데이터 복사
raw_data = heart.copy()

#앞에서 했던대로 범주형/연속형 컬럼 나누기
cat_cols = ['sex','exng','caa','cp','fbs','restecg','slp','thall']
con_cols = ["age","trtbps","chol","thalachh","oldpeak"]

#전처리를 위해 get_dummies()사용
heart = pd.get_dummies(heart, columns=cat_cols, drop_first=True)
heart.head()

 

머신러닝에서 모형에 데이터를 적합시키기 전, 반드시 데이터들을 컴퓨터가 인식할 수 있는 숫자형으로 바꿔주는 전처리 작업이 필요하다.

 

 

이때 범주형 변수들을 단순히 수치형 데이터로 바꿔주면 데이터 간에 관계성이 생긴다. 하지만 범주형 변수들은 값 간에 상관관계가 있으면 안된다.

 

 

예를 들어 계절 컬럼에 1:봄 2:여름 3:가을 4:겨울 이라고 했을 때 수치형으로 바꾸면 1+2=3이라는 관계성이 생기는데 실제로는 봄+여름=가을이라는건 말이 안된다. 그렇기 때문에 이런 카테고리형 변수들에 대해서는 get_dummies( )함수를 이용해서 관계성이 없는 가변수로 전처리를 해준다.

 

 

X = heart.drop(['output'], axis=1)
y = heart[['output']]

scaler = RobustScaler()

X[con_cols] = scaler.fit_transform(X[con_cols])
X.head()

 

이제 X변수와 y변수를 분리해준다. 타깃이 output이므로 X변수에는 output만 drop시키고 나머지 컬럼을 전부 넣고 y에는 output 컬럼을 넣는다. 그 다음으로는 RobustScaler로 정규화를 한번 해준다.

 

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

 

train_test_split으로 train set, test set까지 나눠주면 끝!

 

 

모델 적합

(1)로지스틱회귀

logreg = LogisticRegression()
logreg.fit(X_train, y_train)

y_pred_proba = logreg.predict_proba(X_test)  #predict_proba : 예측확률
y_pred = np.argmax(y_pred_proba, axis=1)  #np.argmax : 최댓값의 색인 위치

accuracy_score(y_test, y_pred)
>>>0.9016393442622951

로지스틱 회귀 모델에 적합시켜보면 정확도가 90%나 된다.

 

y_pred_prob = y_pred_proba[:,1]

fpr, tpr, thresholds = roc_curve(y_test, y_pred_prob)

plt.plot([0,1], [0,1], "k--", "r+")
plt.plot(fpr, tpr, label='LogisticRegression')
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.title('LogisticRegression ROC curve')
plt.show()

ROC 커브도 한 번 그려봐주고..

 

 

(2)Tree 모델

dt = DecisionTreeClassifier(random_state=42)
dt.fit(X_train, y_train)
y_pred = dt.predict(X_test)
accuracy_score(y_test, y_pred)
>>>0.7868852459016393

rf = RandomForestClassifier()
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
accuracy_score(y_test, y_pred)
>>>0.8360655737704918

gbt = GradientBoostingClassifier(n_estimators=300, max_depth=1, subsample=0.8, max_features=0.2, random_state=42)
gbt.fit(X_train, y_train)
y_pred = gbt.predict(X_test)
accuracy_score(y_test, y_pred)
>>>0.8688524590163934

 

결정트리, 랜덤포레스트, 그라디언트 부스트 3개에 적합시키고 accuracy_score를 비교해보면 그라디언트 부스트가 정확도가 가장 높다. 

 

 

결론적으로는 로지스틱 회귀가 정확도 90%로 가장 높은 성능을 보인다.