앎을 경계하기

DAFIT/906 - 머신러닝으로 당뇨병 예측

<DAFIT> 06 머신러닝을 통한 당뇨병 예측 - 02 NaN값,NULL 값 처리하기 (+ 삽질연속, 실망스러운 결과..)

양갱맨 2019. 11. 23. 00:53

 


이번에는 데이터 결측치를 처리하는 문제였다.

데이터 결측치를 처리하는 방법론들이 대표적인게 있을 것 같아서 찾아보니 역시나 다양한 방법들이 있었다.

https://m.blog.naver.com/tjdudwo93/220976082118

 

데이터 분석 최대의 적! 결측치(NA값)처리하기

이번 시간은 데이터 전처리 과정에서 가장 중요하다고 해도 과언이 아닌(물론 다 중요하지...

blog.naver.com

이 블로그를 참고하면서도 잘 모르는 내용들이 있어서 다핏 단톡방에도 질문...

도움이 되는 답변들을 받았다!

 

일단은 데이터를 받으면 데이터들의 피쳐들간의 상관관계를 파악하라는 조언을 받아

데이터분석 모르지만,,ㅎㅎ 이것저것 찾아서 적용해보았다.

각 피처들에 대한 정보는 다음과 같다.

preg: 임신 횟수

plas: 혈장 포도당 농도

pres: 혈압

skin: 삼두근(?) 피부 주름 두께

insu: 2시간 혈청 인슐린

mass: 체중/(키^2)

pedi: 당뇨병 혈통 기능

age: 나이

class: 당뇨병인가 아닌가

맨 아래는 각 피처 데이터들의 평균과 표준편차이다.

 

원본 데이터

위와 같이 생긴 데이터들의 각 피쳐들간 상관관계를 Pandas를 사용해서 확인할 수 있다고 한다.

단 한줄만으로.

df.corr()

양수이면 양의 상관관계에, 음수이면 음의 상관관계가 있는 것이다.

사실 이렇게 표로 보면 눈에 잘 안들어오기 때문에 heatmap을 그려서 시각적으로 확인했다.

import matplotlib.pyplot as plt
import seaborn as sns

plt.figure(figsize=(8,8))
sns.heatmap(data=df.corr(),annot=True, linewidths=.5)  # 상관계수 : 기본이 피어슨 상관계수 사용

근데 사실.. 이걸 보면서 pres와 뚜렷한 상관관계를 보이는 특징이 무엇인지 잘 모르겠었음..

제일 높은게 0.28인데 0.5를 넘는 것도 아니구... 그래도 일단 특징보단 높아서

'age','preg','plas','mass','skin' 이렇게 5가지를 학습할 피처들로 사용했다.

이걸 하면서도 이게 맞는지,, 사실 잘 모르겠음.. 누가 좀 알려줘요 ㅠㅠ

딥러닝으로 예측하기 위해서 모델 구성을 하고 학습을 시켰다.

import tensorflow as tf

model = tf.keras.models.Sequential([
                                    tf.keras.layers.Dense(32, kernel_initializer='normal', activation = "relu"), 
                                    tf.keras.layers.Dense(256, kernel_initializer='normal', activation = "relu"),
                                    tf.keras.layers.Dense(512, kernel_initializer='normal', activation = "relu"),
                                    tf.keras.layers.Dense(512, kernel_initializer='normal', activation = "relu"),
                                    tf.keras.layers.Dense(512, kernel_initializer='normal', activation = "relu"),
                                    tf.keras.layers.Dense(128, kernel_initializer='normal', activation = "relu"),
                                    tf.keras.layers.Dense(64, kernel_initializer='normal', activation = "relu"),
                                    tf.keras.layers.Dropout(rate=0.5),
                                    tf.keras.layers.Dense(1, kernel_initializer='normal', activation = "relu")
])

model.compile(loss='mean_squared_error',
              optimizer='adam',
              metrics=['MeanSquaredError'])
              
model.fit(train_x, train_y, epochs=100, batch_size=32, validation_split=0.2)

loss가 줄어들긴하지만,, 일단 normalization이 안되어있어서 그런지 loss값이 굉장히 컸다.

모르니까 일단은 계속 해보자..

학습을 다 시키고서 prediction 결과를 보니,, 여전히 말이 안되는 값들이 예측값으로 나와있었다.

 

prediction =  model.predict(presdf)
prediction

좌절..

어떻게 해야 잘 할 수 있을까..엉엉

진짜 잘해보고 싶었는데,,

강화학습 공부만 했지 이런 데이터를 가지고 실제로 데이터 전처리하고 분석을 하는건 처음이라 부족하다는 것을 너무 많이 느꼈다...

일단 문제는 풀어야하니까 힌트를 봤다.

음..? mean..? 평균값을 이용해라..? 음... 내가 생각했던 그 방법을 쓰면 되는 것인가..?

하지만 결측값 대체로 mean값은 데알못인 내가 봐도 쓰면 안될 것 같았다.

편향이 생길테니까..

일단 지푸라기라도 잡는 심정으로 그냥 내가 생각했던 제일 단순한 방법을 적용했다.

import pandas as pd
data = pd.read_csv('/content/drive/My Drive/다핏문제/906/dataset_37_diabetes.csv')
preszero_data = data.replace({'pres':0},{'pres':None})

pres는 0이 될 수 없기 때문에 0인 값들을 None으로 바꾸고 None값을 없앤 dataset의 median 값을 None 자리에 대체해줬다.

preszero1_data = preszero_data.dropna()
preszero_data = data.replace({'pres':0},{'pres':None})
preszero_data = preszero_data.fillna(preszero1_data.pres.median())

 그 다음으로 mass = 체중/(키^2)도 0.0이 될 수 없으니 median 값을 구해서 대체해줬다.

masszero_data = preszero_data.replace({'mass':0.0},{'mass':None})
masszero1_data = masszero_data.dropna()
masszero_data = masszero_data.fillna(masszero1_data.mass.median())

 

데이터의 분포가 어떻게 바뀌었는지 확인해보자.

import matplotlib.pyplot as plt
import seaborn as sns

f, axes = plt.subplots(2)
sns.distplot(masszero_data['pres'], ax=axes[0],color='blue')
sns.distplot(data['pres'], ax=axes[1], color='red')
plt.show()

 혈압에 대한 분포는 원래 빨간색처럼 0값이 있었지만 중간값으로 채워지면서 파란색 분포로 변했다.

f, axes = plt.subplots(2)
sns.distplot(masszero_data['mass'], ax=axes[0],color='blue')
sns.distplot(data['mass'], ax=axes[1], color='red')
plt.show()

mass도 분포를 보니 원래 0.0값이 있던 빨간 분포에서 파랗게 분포가 변경된것을 볼 수 있다.


일단은 이렇게 결측치를 median으로 변경해서 사용했으나..찝찝..

조금 더 공부를 하고서 이 부분은 다시 손을 대봐야겠다.

더보기

혹시라도 이 부분에 대해서 설명이나 조언을 해주실 수 있는 분께서는 reinforcement@kakao.com 으로 메일주세요ㅠㅠ