당뇨병 예측하기

Reddit 에서 흥미로운 글을 봤어요. 인공신경망을 이용해서 당뇨를 예측하는 튜토리얼이었죠. 파이썬을 이용해서 15줄의 코드가 전부였습니다.

0. 기계학습이라고?

2016년도 이세돌을 이겼던 AlphaGO를 기억하시나요? AlphaGO라는 인공지능을 바로 기계학습으로 만들었습니다.

기계 학습 또는 머신 러닝(영어: machine learning)은 인공 지능의 한 분야로, 컴퓨터가 학습할 수 있도록 하는 알고리즘과 기술을 개발하는 분야를 말한다. 가령, 기계 학습을 통해서 수신한 이메일이 스팸인지 아닌지를 구분할 수 있도록 훈련할 수 있다. - wikipedia

모든 경우의 수를 사람이 코딩할 필요가 없이 최소한의 것만 해주면, 인공 지능이 알아서 한다. 그것이 기계학습의 매력이죠. 기계학습에도 여러 종류가 있습니다. 우리가 이번에 사용할 것은 인공 신경망이라는 것입니다.

인공신경망

인공신경망(artificial neural network, ANN)은 기계학습과 인지과학에서 생물학의 신경망(동물의 중추신경계중 특히 뇌)에서 영감을 얻은 통계학적 학습 알고리즘이다. - wikipedia

어떻게 인공신경망을 만드냐고요? 파이썬에는 이미 기계학습에 사용되는 프레임워크(예를 들면 TensorFlow)가 존재해서, 우리는 그냥 쓰기만 하면되요!

1. Keras를 사용할 거에요.

keras

Keras is a high-level neural networks API, written in Python and capable of running on top of TensorFlow, CNTK, or Theano. It was developed with a focus on enabling fast experimentation.

Keras는 다음과 같은 특징이 있습니다.

  • 쉽게 그리고 빠르게 코딩이 가능
  • CPU 와 GPU 자원을 문제없이 사용
  • 파이썬 2.7 - 3.6을 지원

자세한 내용은 공식 사이트를 방문하세요.

데이터 세트 설명

사용한 데이터 세트는 Pima Indians Diabetes Data Set 입니다. 출처는 링크를 확인하세요.

미국 원주민 중 Pima 족은 원래는 당뇨병의 유병율이 적었는데, 서구식 식습관에 의해 급속도로 당뇨병에 걸렸습니다. 그래서 당뇨병을 연구하는데 귀중한 데이터로 사용되고 있습니다.

데이터 세트는 CSV 포멧이고 총 9가지의 속성으로 구성되어 있습니다.

  1. 임신횟수
  2. 글루코스 내성(glucose tolerance)실험 후의 혈당수치
  3. 확장기 혈압(mm Hg)
  4. 상완 삼두근 피부 두께 (mm)
  5. 혈액내 인슐린 수치 (mu U/ml)
  6. BMI(비만도) 수치 (weight in kg/(height in m)^2)
  7. 당뇨병 가족력: 계산식은 데이터세트의 출처에서 확인하세요.
  8. 나이 (years)
  9. 당뇨병 여부 (0 or 1; 1은 발병)

출처

원작자의 코드를 확인하고 싶다면 다음 링크를 확인하세요.

2. 이제 실습을 해봅시다.

In [2]:
# 필요한 모듈을 불러들입니다.
from keras.models import Sequential
from keras.layers import Dense
import numpy
from urllib import request
import matplotlib.pyplot as plt

%matplotlib inline

# 데이터 세트의 URL을 설정
url = "http://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
f = request.urlopen(url)

# random seed for reproducibility
numpy.random.seed(2)

# 데이터 세트를 불러옵니다.
dataset = numpy.loadtxt(f, delimiter=",")
Using TensorFlow backend.

이걸로 데이터 세트는 준비가 되었습니다.

모델 만들기

다음으로 Keras를 이용해 간단한 모델을 만들고, 800번의 학습(epochs)을 해보겠습니다. 800번 정도 실행시키면 시간이 좀 걸립니다. 기다려 주세요.

In [3]:
# 데이터세트를 두 가지 원인(X) 과 결과(Y)로 나누어 줍니다.
X = dataset[:, 0:8]
Y = dataset[:, 8]

# create model, add dense layers one by one specifying activation function
model = Sequential()
model.add(
    Dense(12, input_dim=8, activation="relu")
)  # input layer requires input_dim param
model.add(Dense(15, activation="relu"))
model.add(Dense(8, activation="relu"))
model.add(Dense(10, activation="relu"))
model.add(
    Dense(1, activation="sigmoid")
)  # sigmoid instead of relu for final probability between 0 and 1

# compile the model, adam gradient descent (optimized)
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])

# call the function to fit to the data (training the network)
# verbose=0 는 프로그래스를 숨깁니다.
history = model.fit(X, Y, epochs=800, batch_size=10, verbose=0)

# 모델의 정확도를 계산합니다.
scores = model.evaluate(X, Y)
print("\n%s: %.2f%%" % (model.metrics_names[1], scores[1] * 100))
768/768 [==============================] - 0s 80us/step

acc: 87.89%

우리의 모델이 학습결과 87.89% 라는 정확도를 가지게 되었습니다.

2. 시각화하기

이제 다 끝났습니다. 다음으로는 Keras가 학습을 반복할 때마다 정확도가 얼마나 올라가는지 시각화를 해보겠습니다.

In [3]:
# Get the figure and the axes
fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, sharey=False, figsize=(10, 5))

# 모델의 정확도를 그립니다.
ax0.plot(history.history["acc"])
ax0.set(title="model accuracy", xlabel="epoch", ylabel="accuracy")

# 모델의 오차를 그립니다.
ax1.plot(history.history["loss"])
ax1.set(title="model loss", xlabel="epoch", ylabel="loss")
Out[3]:
[Text(0,0.5,'loss'), Text(0.5,0,'epoch'), Text(0.5,1,'model loss')]
No description has been provided for this image

결과를 보니, 한 800번 정도 학습하면 꽤 정확한 모델을 얻을 수 있네요.

3. 마치며,

모델을 만들었다면, 이제 모델을 유용하게 사용할 시간입니다. 가상의 환자 데이터를 만들어 그 환자가 당뇨에 걸릴 확률을 알아보겠습니다.

patient_1

  1. 임신한 적 없음
  2. 글루코스 내성(glucose tolerance)실험 후의 혈당수치는 137
  3. 확장기 혈압은 90(mm Hg)
  4. 상완 삼두근 피부 두께는 35(mm)
  5. 혈액내 인슐린 수치는 168 (mu U/ml)
  6. BMI(비만도) 수치는 43.1
  7. 당뇨병 가족력은 2.288
  8. 나이 (years)는 33살

이라고 가정합니다.

In [4]:
# 가상의 환자 데이터 입력
patient_1 = numpy.array([[0, 137, 90, 35, 168, 43.1, 2.288, 33]])

# 모델로 예측하기
prediction = model.predict(patient_1)

# 예측결과 출력하기
print(prediction * 100)
[[30.039745]]

우리의 모델에 따르면, patient_1는 당뇨병에 걸릴 확률이 약 30% 입니다.