빅데이터 | 머신러닝 | 딥러닝/딥러닝

[딥러닝 기초] Neural Network (use cancer dataset/classfication)

냠냠:) 2020. 4. 19. 03:28

[이 글은 "Do it 딥러닝 입문" 책을 보고 공부한 내용을 복습하고자 정리한 글입니다.]

 

목표 - 유방암 데이터 셋으로부터 모델을 만들고 테스트 후 정확도를 확인한다.

 

sklearn(Scikit-learn이란?

- 파이썬에 있는 머신러닝 라이브러리 중 하나로, 분류(classification), 회귀(regression), 군집화(clustering), 의사결정 트리(decision tree) 등의 다양한 알고리즘을 적용할 수 있는 다양한 함수들을 제공하는 라이브러리 

 

[공부 중 궁금했던 것과 사용한 함수들을 정리]

 

1. from sklearn.dataset import load_breast_cancer

- 사이킷런에서 유방암 데이터를 로드

 

2. plt.boxplot(cancer.data)

- cancer.data에 있는 열(column)의 데이터를 상자와 수염을 이용해 그린 그래프

참고 링크 : https://rfriend.tistory.com/410

 

3. cancer.feature_names[[3,13,23]]

- 각 인덱스에 해당하는 열의 특성(이름)을 볼 수 있음.

 

4. np.unique(target, return_counts=)

- target안에 고유한 값의 개수를 센 다음 반환

 

5. from sklearn.model_selection import train_test_split

- 주어진 데이터 셋에서 훈련 데이터와 테스트 데이터로 나누기 위한 모듈

 

6. train_test_split(x, y, stratify=y, test_size, random_state=42)

- stratify : 훈련 데이터를 나눌 때 골고루 나눠져야 하는데 y로 주게 되면 y를 기준으로 균형 있게 나눠진다.

- test_size : default는 75 : 25지만 우리는 80 : 20으로 나누기 위해 0.2르 주었다.

- random_state : 무작위로 데이터 세트를 섞음 다음 나누는 함수

 

7. forpass(x):

- hypothesis를 구하는 함수 정방향 계산이라고도 불린다. x값과 w값을 곱하구 b를 더해 예측 값을 구한다.

 

8. backprop(x, err):

- err는 실제값과 예측값의 차이이다. w 값은 x * err, b 값은 1 * err을 준다. 그레이디언트를 계산하는 것이다.

 

9. np.random.permutation(np.arange(len(x)))

- x값의 길이 즉, 행의 인덱스를 섞어서 훈련을 랜덤 하게 되게(효율적으로)하는 용도로 사용한다.

 

10. np.clip(값, 범위, 범위)

- 값의 주어진 범위 밖으로 나가면 양 끝의 값으로 잘라낸다.

- 섞으므로서 우리는 확률적 경사 하강법에서부터 배치 경사 하강법을 구현할 수 있다.

 

11. 모델 생성의 메커니즘

     w값과 b값을 랜덤으로 부여(여기선 None으로 줌)

->  w값과 x값을 forpass 해주기 위해 w값을 x의 열의 수로 맞춰준다.(행렬의 곱은 행열*열행이 충족돼야 하므로)

->  forpass로 예측 값 즉, z값을 구해준다.

->  z값을 activation함수에 넣어주어 0 ~ 1 사이의 값(a)으로 바꿔준다. (sigmoid)

->  실제 값과 예측 값을 빼주어서 오차율을 구한다.(여기서 음수인 이유는 y_hat은 w와 b의 함수이기 때문이다.)

->  backprop을 이용해서 w와 b를 업데이트를 해준다.

->  로지스틱 손실 함수를 구해준다.

->  epoch만큼 모델이 학습되면 x_test값과 y_test으로 모델의 정확도를 판단해준다.

 

 

 

Neural Network(using cancer2)
In [1]:
#유방암 데이터 세트 준비
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
print(cancer.data.shape, cancer.target.shape)
(569, 30) (569,)
In [2]:
cancer.data[:3]
cancer.target[:100]
Out[2]:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
       0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0,
       1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0,
       1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0])
In [3]:
import numpy as np
import matplotlib.pyplot as plt
plt.boxplot(cancer.data)
plt.show()
In [4]:
cancer.feature_names[[3,13,23]]
Out[4]:
array(['mean area', 'area error', 'worst area'], dtype='<U23')
In [5]:
np.unique(cancer.target, return_counts=True)
#cancer.target에 있는 수를 카운트해서 반환
Out[5]:
(array([0, 1]), array([212, 357], dtype=int64))
In [6]:
# 훈련 데이터 저장
x = cancer.data
y = cancer.target
In [7]:
# 하나의 데이터 셋에서 훈련데이터와 테스트데이터로 나눈다.
from sklearn.model_selection import train_test_split
In [8]:
x_train, x_test, y_train, y_test = train_test_split(x, y, stratify=y, test_size=0.2, random_state=42)
In [9]:
np.unique(y_train, return_counts=True)
Out[9]:
(array([0, 1]), array([170, 285], dtype=int64))
In [10]:
class SingleLayer():
    def __init__(self):
        self.w = None       # 데이터 특성이 많기 때문에 가중치를 미리 초기화하지 않음.
        self.b = None
        self.losses = []
        
    def forpass(self, x):
        z = np.sum(x * self.w) + self.b   # 직선의 방정식 즉 hypothesis #np.sum을 사용하면 1차원 넘파이배열에서 배열의 요소끼리 사칙연산을 할 수 있음.
        return z
    
    def backprop(self, x, err):
        w_grad = x * err                   #가중치에 대한 그레이디언트 계산
        b_grad = 1 * err                   #절편에 대한 그레이디언트 계산
        return w_grad, b_grad
    
    def fit(self, x, y, epochs=100):
        self.w = np.ones(x.shape[1])       #가중치를 초기화하는데 x의 shape과 똑같고 1채움 즉 각 행값 
        self.b = 0
        for i in range(epochs):
            loss = 0
            indexes = np.random.permutation(np.arange(len(x))) #인덱스를 섞음. 데이터가 섞여서 훈련될수록 손실 함수의 값이 효율적으로 줄어듬
            for i in indexes:
                z = self.forpass(x[i])                     #정방향 계산
                a = self.activation(z)                     #activation함수 적용
                err = -(y[i] - a)                          #실제값과 예측값 오차계산
                w_grad, b_grad = self.backprop(x[i], err)  #역방향 계산
                self.w -= w_grad                           #업데이트
                self.b -= b_grad
                a = np.clip(a, 1e-10, 1-1e-10)             #인잔힌 로그 계산을 위해 클리핑 한 후 손실을 누적
        
                loss += -(y[i] * np.log(a) + (1-y[i]) * np.log(1-a))  #에포크마다 평균 손실을 저장
            self.losses.append(loss/len(y))
                
    def activation(self, z):
        a = 1 / (1 + np.exp(-z))
        return a
    
    def predict(self, x):
        z = [self.forpass(x_i) for x_i in x]              #hypothesis를 구해 반환
        return np.array(z) > 0                            #스텝 함수 적용
    
    def score(self, x, y):
        return np.mean(self.predict(x)==y)
In [11]:
layer = SingleLayer()
layer.fit(x_train,y_train)
layer.score(x_test,y_test)
C:\Users\USER\Anaconda3\lib\site-packages\ipykernel_launcher.py:35: RuntimeWarning: overflow encountered in exp
Out[11]:
0.9298245614035088
In [12]:
plt.plot(layer.losses)
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()
반응형