[TensorFlow] 심장질환 예측 Start

BioinformaticsAndMe









[TensorFlow] 심장질환 예측


: TensorFlow 2.0 에서 만들어진 DNN(심층신경망) 모델에 근거하여, 환자데이터로부터 심장병 유무를 예측

: 심장병은 사망률이 높은 질환으로 정확한 예측을 위해선, 훨씬 더 복잡한 데이터와 상호관계 분석이 필요

*아래 예제는 간단한 파일럿테스트

: 텐서플로우를 통한 심장질환 예측은 아래 순서로 진행

1) 데이터 준비

2) 환자데이터 살펴보기

3) 데이터 전처리

4) Neural Network 모델 만들기

5) 모델 Training

6) 심장질환 예측




1. 데이터 준비


: 분석데이터 다운로드 → https://www.kaggle.com/ronitf/heart-disease-uci (kaggle 가입 필요)

*heat.csv - 303명 환자기록과 14가지 속성(변수)

# 분석에 필요한 라이브러리 로딩 !pip install tensorflow-gpu==2.0.0-alpha0 import numpy as np import tensorflow as tf from tensorflow import keras import pandas as pd import seaborn as sns from pylab import rcParams import matplotlib.pyplot as plt from matplotlib import rc from google.colab import drive from sklearn.model_selection import train_test_split %matplotlib inline sns.set(style='whitegrid', palette='muted', font_scale=1.5) rcParams['figure.figsize'] = 14, 8 RANDOM_SEED = 42 np.random.seed(RANDOM_SEED)

# 구글드라이브 마운트 및 파일경로 지정

drive.mount("/content/drive")

heart_csv_path = "/content/drive/My Drive/Colab Notebooks/tensorflow-2/data/heart.csv"

# 데이터 로딩 후, 출력

data = pd.read_csv(heart_csv_path)

data.describe()

#age - 나이 #sex - (1 = 남성; 0 = 여성) #cp - 가슴 통증 유형(0, 1, 2, 3, 4) #trestbps - 안정 혈압(병원 입원시 mm Hg) #chol - 혈청 콜레스테롤(mg/dl) #fbs - (공복 혈당 > 120 mg/dl)(1 = true; 0 = false) #restecg - 안정 심전도 결과(0, 1, 2) #thalach - 최대 심박동수 #exang - 협심증 유발 운동(1 = yes; 0 = no) #oldpeak - 비교적 안정되기까지 운동으로 유발되는 ST depression #slope - 최대 운동 ST segment의 기울기 #ca - 형광 투시된 주요 혈관의 수(0-3) #thal - (3 = 보통; 6 = 해결된 결함; 7 = 해결가능한 결함) #target - 심장병 진단(1 = true; 0 = false)

# 데이터 구조 확인

data.shape

(303, 14)

# 데이터 변수 확인

data.columns

Index(['age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg', 'thalach', 'exang', 'oldpeak', 'slope', 'ca', 'thal', 'target'], dtype='object')




2. 환자데이터 살펴보기


: 환자데이터를 직접 시각화하여, 데이터의 특징을 직관적으로 이해

# 303명의 환자에서 심장병 유무를 확인

f = sns.countplot(x='target', data=data) f.set_title("Heart disease presence distribution") f.set_xticklabels(['No Heart disease', 'Heart Disease']) plt.xlabel("")

# 303명의 환자에서 심장병 유무를 남녀로 나누어 확인

f = sns.countplot(x='target', data=data, hue='sex') plt.legend(['Female', 'Male']) f.set_title("Heart disease presence by gender") f.set_xticklabels(['No Heart disease', 'Heart Disease']) plt.xlabel("");

# 변수(Feature) 사이에서의 상관관계 정도를 Heatmap으로 구현

# +1에 가까울수록, positive correlation

# -1에 가까울수록, negative correlation

heat_map = sns.heatmap(data.corr(method='pearson'), annot=True, fmt='.2f', linewidths=2) heat_map.set_xticklabels(heat_map.get_xticklabels(), rotation=45);




3. 데이터 전처리


: 보유한 데이터는 범주형/숫자형의 혼합 형태로, 원활한 텐서플로우 모델링을 위해 데이터 전처리가 필요함

: 머신러닝 모델에서는 범주형/숫자형을 떠나 모든 Feature들이 숫자로 처리됨

# feater column은 'raw 데이터'와 '모델링하는 데이터'를 연결짓는 브릿지 역할

feature_columns = [] # 수치형 열(Numeric col)은 실수값을 변형시키지 않고 그대로 전달

for header in ['age', 'trestbps', 'chol', 'thalach', 'oldpeak', 'ca']: feature_columns.append(tf.feature_column.numeric_column(header)) # 버킷형 열(Bucketized column)은 수치값을 구간을 나누어 범주형으로 변환 age = tf.feature_column.numeric_column("age") age_buckets = tf.feature_column.bucketized_column(age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65]) feature_columns.append(age_buckets) # 범주형 열(Categorical column)은 특정 문자열을 수치형으로 매핑하여 전달 data["thal"] = data["thal"].apply(str) thal = tf.feature_column.categorical_column_with_vocabulary_list( 'thal', ['3', '6', '7']) thal_one_hot = tf.feature_column.indicator_column(thal) feature_columns.append(thal_one_hot) data["sex"] = data["sex"].apply(str) sex = tf.feature_column.categorical_column_with_vocabulary_list( 'sex', ['0', '1']) sex_one_hot = tf.feature_column.indicator_column(sex) feature_columns.append(sex_one_hot) data["cp"] = data["cp"].apply(str) cp = tf.feature_column.categorical_column_with_vocabulary_list( 'cp', ['0', '1', '2', '3']) cp_one_hot = tf.feature_column.indicator_column(cp) feature_columns.append(cp_one_hot) data["slope"] = data["slope"].apply(str) slope = tf.feature_column.categorical_column_with_vocabulary_list( 'slope', ['0', '1', '2']) slope_one_hot = tf.feature_column.indicator_column(slope) feature_columns.append(slope_one_hot) # 임베딩 열(Embedding column)은 범주형 열에 가능한 값이 많을 때 사용 thal_embedding = tf.feature_column.embedding_column(thal, dimension=8) feature_columns.append(thal_embedding) # 교차특성 열(Crossed column)은 여러 특성을 연결하여 하나의 특성으로 만듦

age_thal_crossed = tf.feature_column.crossed_column([age_buckets, thal], hash_bucket_size=1000) age_thal_crossed = tf.feature_column.indicator_column(age_thal_crossed) feature_columns.append(age_thal_crossed) cp_slope_crossed = tf.feature_column.crossed_column([cp, slope], hash_bucket_size=1000) cp_slope_crossed = tf.feature_column.indicator_column(cp_slope_crossed) feature_columns.append(cp_slope_crossed)

# Pandas 데이터프레임 → Tensorlfow 데이터셋

def create_dataset(dataframe, batch_size=32): dataframe = dataframe.copy() labels = dataframe.pop('target') return tf.data.Dataset.from_tensor_slices((dict(dataframe), labels)) \ .shuffle(buffer_size=len(dataframe)) \ .batch(batch_size)

# 전체데이터를 Training set과 Test set으로 나누기

train, test = train_test_split(data, test_size=0.2, random_state=RANDOM_SEED)

train_ds = create_dataset(train) test_ds = create_dataset(test)




4. Neural Network 모델 만들기


# 오버피팅을 줄이기 위해, Dense layer 사이에 Dropout layer 배치

model = tf.keras.models.Sequential([ tf.keras.layers.DenseFeatures(feature_columns=feature_columns), tf.keras.layers.Dense(units=128, activation='relu'), tf.keras.layers.Dropout(rate=0.2), tf.keras.layers.Dense(units=128, activation='relu'), tf.keras.layers.Dense(units=1, activation='sigmoid') ])




5. 모델 Training


# 모델 컴파일 후, 학습되면서 생기는 손실과 정확도 지표 출력

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) history = model.fit(train_ds, validation_data=test_ds, epochs=100, use_multiprocessing=True)

# model.evaludate 함수로 Test set 정확도 평가 model.evaluate(test_ds)

2/2 [==============================] - 0s 23ms/step - loss: 0.3431 - accuracy: 0.8852 [0.3430721387267113, 0.8852459]

# 모델의 정확도 시각화 plt.plot(history.history['accuracy']) plt.plot(history.history['val_accuracy']) plt.title('model accuracy') plt.ylabel('accuracy') plt.xlabel('epoch') plt.ylim((0, 1)) plt.legend(['train', 'test'], loc='upper left');

# 모델의 손실 시각화 plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.title('model loss') plt.ylabel('loss') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show()




6. 심장질환 예측


# 만들어진 DNN 모델로 심장질환을 예측

# 앞서 얻은 accuracy에 상관없이, precision/recall/f1-score가 높지 않음을 확인

*precision = 정밀도

*recall = 재현율

*f1-score = 정밀도와 재현율의 조화 평균

from sklearn.metrics import classification_report, confusion_matrix

predictions = model.predict(test_ds)

bin_predictions = tf.round(predictions).numpy().flatten()

print(classification_report(y_test.values, bin_predictions))

precision recall f1-score support 0 0.59 0.66 0.62 29 1 0.66 0.59 0.62 32 micro avg 0.62 0.62 0.62 61 macro avg 0.62 0.62 0.62 61 weighted avg 0.63 0.62 0.62 61

# Confusion matrix(혼동 행렬)로 결과 시각화

class_names = [0,1] fig,ax = plt.subplots() tick_marks = np.arange(len(class_names)) plt.xticks(tick_marks,class_names) plt.yticks(tick_marks,class_names) sns.heatmap(pd.DataFrame(cnf_matrix),annot=True,cmap="Blues",fmt="d",cbar=False) ax.xaxis.set_label_position('top') plt.tight_layout() plt.ylabel('Actual label') plt.xlabel('Predicted label');





#Reference

1) https://towardsdatascience.com/heart-disease-prediction-in-tensorflow-2-tensorflow-for-hackers-part-ii-378eef0400ee

2) https://colab.research.google.com/drive/13EThgYKSRwGBJJn_8iAvg-QWUWjCufB1

3) https://www.kaggle.com/ronitf/heart-disease-uci

4) https://www.tensorflow.org/tutorials/structured_data/feature_columns

5) https://locslab.github.io/Tensorflow-feature-columns(1)/





[TensorFlow] 심장질환 예측 End

BioinformaticsAndMe

+ Recent posts