본문 바로가기
데이터 과학 관련 스터디/모두의 딥러닝

[모두의 딥러닝] 11장 데이터 다루기

by inhovation97 2020. 7. 11.

11장은 10장처럼 간단하게 인공 신경망을 구현하지만, 약간의 데이터를 다루는 법이 추가되어 있습니다.

아주 기초적인 부분이라서 어렵지 않고, 코드 하나 하나 설명이 친절히 나와있어요.

이 책의 큰 장점이죠!

데이터는 pima indian입니다. 인디언 768명으로부터 당뇨병의 여부를 예측하는 문제입니다.

 

 

 

<describe함수>

 

먼저 pandas를 이용해 각 column의 네임을 지정해주면서 DataFrame을 불러옵니다.

그리고나서 describe함수를 통해 기초 통계량을 확인합니다.

decribe 함수는 각 컬럼들의 정보들을 한눈에 볼 수 있어서 컬럼이 적을 때는 꽤나 유용합니다.

이렇게 각 컬럼들의 기초 통계량과 컬럼들의 정보를 알아가면서 데이터 분석을 시작합니다. 

 

<groupby 함수>

 

우리가 가장 궁금하고 예측해야할 컬럼은 바로 'class' 당뇨병의 발생 여부입니다. 이를 pregnant(과거 임신 횟수)와 짝지어 집중적으로 보고싶을 때는 이렇게 groupby함수를 이용해서 봅니다.

groupby함수는 특히나 몇개의 변수들을 따로 시각화할때 매우 유용합니다.

sort_values는 그저 pregnant함수를 중심으로 오름차순으로 정리하기위해 쓴 함수입니다.

 

<heatmap 함수>

 

다음은 상관관계를 분석하기위해 히트맵을 그립니다.

heatmap은 변수와 변수사이의 선형적 관계가 있는지를 한눈에 보기 위해 시각화하는 함수입니다.

시각화는 데이터를 분석하는데에 있어서 인사이트를 뽑아내기위한 굉장히 중요한 과정으로 EDA를 할때, 많이 시도합니다.

그중에서도 특히 히트맵은 각 변수사이의 관계를 보기위해 많이 다루는데, 유의할 점은 히트맵은 변수와 변수 사이의 선형적인 관계를 알기위해 하는 것이지, 아예 독립인지는 알 수 없습니다.

이 부분은 굉장히 중요한데, 상관계수가 낮게 나왔다고 두 변수를 독립이라고 말할 수 없다는 것 입니다. 또 높게 나왔다고 정말로 두 변수는 관계가 깊다고 할 수도 없죠.

 

전자부터 예를 들자면, 두 변수는 상관계수가 너무 낮게 나왔다고 칩시다. 하지만 이 두 변수는 관계가 적다고 할 수가없는게 선형적인 관계는 아니지만 비선형적인 관계는 있을 수 있다는 것입니다. 두 변수를 산점도로 그려봤을 때, 이차 함수의 관계를 띄면 상관계수는 낮게 나올테지만, 관계가 없는 독립이 아니라 비선형적인 관계가 있는 것이지요. 이는 상관계수의 수식을 한 번 자세히 살펴보면 쉽게 이해가 갑니다. 

 

후자두 변수가 상관계수가 높게 나왔다고 생각해봅니다. 하지만 가령 두 변수중 하나는 흡연, 하나는 사람의 키라고 칩시다. 둘이 0.8 이상의 높은 상관계수가 나왔다고 사람의 키가 흡연과 관련이 있을까요?? 물론 여성에 비해 남성이 많이 피기야 하겠지만, 키 큰 사람일수록 흡연자가 많다는 것은 너무나 비논리적입니다.

 

이렇듯, 히트맵은 그저 한 인사이트를 가져가는 정도로 그려보는 것이지, 높게 나오거나 적게 나왔다고만할게 아니라 그 변수들에 대한 고찰이 필요합니다. 이 부분에 대해서는 나중에 따로 포스팅을 하고 싶네요.

정말로 관계가 있는지는 회귀 분석을 통해야합니다. (회귀 분석도 원래는 검색하면 많이 나오는 파이썬의 함수를 써서 그리는 간단한 그래프가 아니라 정말 단계가 많은 복잡한 과정입니다.)

 

그리고 상관관계는 -1~1 사이에 값을 가지며 절대값이 0.8 이상이면 높은 선형 관계가 있다고 생각하면 됩니다!

 

<히스토그램, kde 플롯>

 

히트맵을 보면 plasma 변수와 class 변수의 상관계수가 가장 높음을 알 수 있습니다. 책을 따라서 두 변수에 대해 시각화를 실행해보겠습니다.

clsss가 1일때, 0일때를 분류하여 히스토그램과 kde플롯을 그렸습니다. 책에는 히스토그램만 나와있는데, kde플롯은 간단히 소개하는 정도로 같이 그려봤습니다.

kde플롯은 확률밀도함수를 시각화한 것으로 보면 되는데 히스토그램의 도수를 연속형으로 바꾸어 각 구간의 확률을 나타내는 그래프 입니다. 범주형 데이터를 한 그래프에 한번에 볼 수 있는 장점이 있습니다.

 

 

grid = sns.FacetGrid(df, col='class')   # 액자를 만들어줌
grid.map(plt.hist, 'plasma', bins=10)   # bins 구간을 잘게 쪼갬
plt.show()

sns.kdeplot(df.loc[df['class']==1,'plasma'],label='class=1')
sns.kdeplot(df.loc[df['class']==0,'plasma'],label='class=0')
plt.show()

# 당뇨병 환자들은 혈압이 대체로 높음

 

<모델 설계>

 

이제 모델을 설계할 단계입니다. 보통 랜덤포레스트나 SVM같은 머신러닝(딥러닝을 제외한)들은 Feature Engineering을 할 때, Feature extraction을 하기 마련입니다. 모델이 분류하는 데에 쓸데없는 피쳐를 빼는 것이지요. 하지만 딥러닝은 모델안에서 자체적으로 이 과정을 거치기 때문에 그 과정은 필요하지않다고 책에서 소개하고 있어요.

사실 이게 장점일수도 단점일수도 있는데,

 

트리 모델은 설명력이 매우 높은 모델이라서 사람들이 모델이 낳은 결과에 대해서 합리적인 이유에 고개를 끄덕이며 이해를 쉽게 할 수 있습니다.

 

하지만 이에비해 딥러닝 모델은 쓸모없는 피쳐들을 알아서 걸러주는 등의 편리함도 있지만, 결과만을 내뱉기 때문에 설명력이 부족하다는 단점이 있습니다.

 

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

# seed 값 생성
np.random.seed(3)
tf.random.set_seed(3)

# 모델의 설정
model = Sequential()
model.add(Dense(12, input_dim=8, activation='relu'))
model.add(Dense(8, activation='relu'))
model.add(Dense(1, activation='sigmoid'))

# 모델 컴파일
model.compile(loss='binary_crossentropy',
             optimizer='adam',
             metrics=['accuracy'])

# 모델 실행
model.fit(X,Y,epochs=200, batch_size=10)

# 결과 출력
print('\n Accuracy: %.4f' % (model.evaluate(X,Y)[1])) # 1이면 loss를 0이면 accuracy를 출력

 

 

 

 

seed값을 정하는 이유는 모델이 쓰는 테이블을 고정시키는 의미입니다. 컴퓨터는 난수를 랜덤으로 뽑는게 아니라 내부적으로 저장되어 있는 랜덤 테이블을 불러오는 거라서 이렇게 seed를 고정해놓으면 같은 테이블을 모델로 돌리는 것이니까 고정된 결과를 얻고 다른 모델과의 비교를 할 수 있게 되는 것입니다.

 

책에서는 seed 값을 고정해도 미세하게 결과 값이 다를 수 있는데 이는 텐서플로를 구동시키는 cuDNN등의 내부 소프트웨어가 자체적으로 랜던 테이블을 생성하기 때문이라고 합니다. 따라서 딥러닝의 여러 결과들을 평균내는 것이 가장 적절하다고 합니다.

 

이번에는 은닉층을 더 추가하고, 손실 함수는 binary crossentropy를 이용했네요.

같은 코드인데도 책에는 정확도가 0.7253이 나왔는데, 저는 0.7721이 나왔네요. 아마 위에서 언급한 랜덤 테이블 때문인것 같습니다.

 

11장 포스팅을 마치겠습니다!

댓글