본문 바로가기
Python (Linux)

34. Python - 4장 연습문제

by #Glacier 2019. 1. 30.
반응형
이 책의 좋은 점 또 하나는 연습문제입니다.
뭔가 생각하게 해보고 복습할 수 밖에 없게 만드는 연습문제들을 보면서 정말 이런 서적들 중에 가성비 갑이라고 생각합니다.
이렇게 세심한 설명과 구성들을 보면 앞으로 이 책을 다 본다면 다른 책도 사볼 수 밖에 없을 것 같아요.
취준생으로서 저는 그렇게 느낍니다..ㅎㅎ;;

4장의 연습문제는 다음과 같습니다.

[연습문제]

1. 수백만 개의 특성을 가진 훈련 세트에서는 어떤 선형 회귀 알고리즘을 사용할 수 있을까요?
수백만 개의 특성이 있는 훈련세트를 가지고 있다면, 
확률적 경사 하강법(SGD)이나 미니배치 경사 하강법을 사용할 수 있습니다.
훈련 세트가 메모리 크기에 맞으면 배치 경사 하강법도 가능합니다.
하지만 정규방정식은 계산 복잡도가 특성 개수에 따라 매우 빠르게 증가하기 때문에 사용할 수 없습니다.

2. 훈련 세트에 있는 특성들이 각기 아주 다른 스케일을 가지고 있습니다.
   이런 데이터에 잘 작동하지 않는 알고리즘은? 그 이유는 무엇일까요? 어떻게 해결할까요?
훈련 세트에 있는 특성의 스케일이 매우 다르면, 비용 함수는 길쭉한 타원 모양의 그릇 형태가 됩니다.
그래서 경사 하강법(GD) 알고리즘이 수렴하는 데 오랜 시간이 걸릴 것입니다.
이를 해결하기 위해서는 모델을 훈련하기 전에, 데이터의 스케일을 조절해야 합니다.
정규방정식은 스케일 조정 없이도 잘 작동하나 특성 수에 주의해야 합니다.
또한 규제가 있는 모델은 특성의 스케일이 다르면 지역 최적점에 수렴할 가능성이 있습니다.
실제로 규제는 가중치가 커지지 못하게 제약을 가하므로 특성값이 작으면 큰 값을 가진 특성에 비해 무시되는 경향이 있습니다.
    
3. 경사 하강법으로 로지스틱 회귀 모델을 훈련시킬 때, 지역 최솟값에 갇힐 가능성이 있을까요?
로지스틱 회귀 모델의 비용 함수는 볼록 함수이므로 경사 하강법이 훈련될 때 지역 최솟값에 갇힐 가능성이 없습니다.
*볼록 함수 -> 두 점 사이를 연결하는 직선이 함수의 곡선과 교차하지 않음

4. 충분히 오랫동안 실행하면 모든 경사 하강법 알고리즘이 같은 모델을 만들어낼까요?
최적화할 함수가 (선형회귀나 로지스틱 회귀처럼) 볼록 함수이고 학습률이 너무 크지 않다고 가정하면, 모든 경사 하강법 알고리즘이 전역 최적값에 도달하고 결국 비슷한 모델을 만들 것입니다. 
하지만 학습률을 점진적으로 감소시키지 않으면 확률적 경사 하강법이나 미니배치 경사 하강법은 진정한 최적점에 수렴되지 못하고 맴돌게 됩니다. (전 포스팅에서 보았음)
이 말은 매우 오랫동안 훈련을 해도 조금씩 다른 모델을 만든다는 뜻입니다.

5. 배치 경사 하강법을 사용하고 에포크마다 검증 오차를 그래프로 나타내봤습니다.
   검증 오차가 일정하게 상승되고 있다면 어떤 일이 일어나고 있는 걸까요?

   어떻게 해결할 수 있나요?
에포크마다 검증 에러가 지속적으로 상승한다면 한 가지 가능성은 학습률이 너무 높고 알고리즘이 발산하는 것일지 모릅니다.
훈련 에러도 올라간다면 이 문제가 확실하며, 학습률을 낮추어야 합니다. 그러나 훈련 에러가 올라가지 않는다면 모델이 훈련 세트에 과대적합 되어 있는 것이므로 훈련을 멈추어야 합니다.

6.  검증 오차가 상승하면 미니배치 경사 하강법을 즉시 중단하는 것이 좋은 방법일까요?
무작위성 때문에 확률적 경사 하강법이나 미니배치 경사 하강법 모두 매 훈련 반복마다 학습의 진전을 보장하지 못합니다.
검증 에러가 상승될 때 훈련을 즉시 멈춘다면 최적점에 도달하기 전에 너무 일찍 멈추게 될 수도 있습니다.
더 나은 방법은 정기적으로 모델을 저장하고 오랫동안 진전이 없을 때, (즉 최상의 점수를 넘어서지 못하면)
저장된 것 중 가장 좋은 모델로 복원하는 것입니다.

7.  우리가 언급한 것 중에서, 어떤 경사 하강법 알고리즘이 가장 빠르게 최적 솔루션의 주변에 도달할까요? 
    실제로 수렴하는 것은 어떤 것인가요? 다른 방법들도 수렴하게 만들 수 있나요?
확률적 경사 하강법은 한 번에 하나의 훈련 샘플만 사용하기 때문에 훈련 반복이 가장 빠릅니다.
그래서 가장 먼저 전역 최적점 근처에 도달합니다. (그다음이 미니배치 경사하강법). 그러나 훈련 시간이 충분하면, 배치 경사 하강법만 실제로 수렴할 것입니다. 앞서 언급한 대로 학습률을 점진적으로 감소시키지 않으면 SGD와 미니배치 GD는 최적점 주변을 맴돌 것입니다.

8.  다항 회귀를 사용했을 때, 학습 곡선을 보니 훈련 오차와 검증 오차 사이에 간격이 큽니다.
     무슨 일이 생긴 걸까요? 이 문제를 해결하는 세 가지 방법은?
검증 오차가 훈련 오차보다 훨씬 더 높으면 모델이 훈련 세트에 과대적합되었기 때문일 가능성이 높습니다.
이를 해결하는 첫 번째 방법은 다항 차수를 낮추는 것입니다. 자유도를 줄이면 과대적합이 훨씬 줄어들 것입니다.
두 번째 방법은 모델을 규제하는 것입니다. 예를 들어 비용 함수에 l2페널티(릿지), l1페널티(라쏘)를 추가합니다.
이 방법도 자유도를 감소시킵니다. 세 번째 방법은 훈련 세트의 크기를 증가시키는 것입니다.

9.  릿지 회귀를 사용했을 때 훈련 오차와 검증 오차가 거의 비슷하고 둘다 높았습니다.
    이 모델에는 높은 편향이 문제인가요, 높은 분산이 문제인가요? 
    규제 하이퍼파라미터 alpha를 높여야 할까요 아니면 줄여야 할까요?
훈련 에러와 검증 에러가 거의 비슷하고 매우 높다면 모델이 훈련 세트에 과소적합되었을 가능성이 높습니다.
즉 높은 편향을 가진 모델입니다. 따라서 규제 하이퍼파라미터 alpha를 감소시켜야 합니다.
      
10. 다음과 같이 사용해야 하는 이유는?

* 평범한 선형 회귀(규제 없는모델) 대신 릿지 회귀
규제가 있는 모델이 일반적으로 규제가 없는 모델보다 성능이 좋습니다.
그래서 평범한 선형 회귀보다 릿지 회귀가 선호됩니다.

* 릿지 회귀 대신 라쏘 회귀
라쏘 회귀는 l1페널티를 사용하여 가중치를 완전히 0으로 만드는 경향이 있습니다. 이는 가장 중요한 가중치를 제외하고는 모두 0이 되는 희소한 모델을 만듭니다. 또한 자동으로 특성 선택의 효과를 가지므로 단지 몇 개의 특성만 실제 유용할 것이라고 의심될 때 사용하면 좋습니다. 확신이 없다면 릿지 회귀를 사용해야 합니다.

* 라쏘 회귀 대신 엘라스틱넷
라쏘가 어떤 경우 (몇 개의 특성이 강하게 연관되어 있거나 훈련 샘플보다 특성이 더 많을 때)에는 불규칙하게 행동하므로 엘라스틱넷이 라쏘보다 일반적으로 선호됩니다. 그러나 추가적인 하이퍼파라미터가 생깁니다. 불규칙한 행동이 없는 라쏘를 원하면 엘라스틱넷에 l1_ratio를 1에 가깝게 설정하면 됩니다.

11. 사진을 낮과 밤, 실내와 실외로 구분하려 합니다. 두 개의 로지스틱 회귀 분류기르르 만들어야 할까요? 
    아니면 하나의 소프트맥스 회귀 분류기를 만들어야 할까요?
실외와 실내, 낮과 밤에 따라 사진을 구분하고 싶다면 이 둘은 배타적인 클래스가 아니기 때문에 (즉 네 가지 조합이 모두 가능하므로) 두 개의 로지스틱 회귀 분류기를 훈련시켜야 합니다.

12. 조기 종료를 사용한 배치 경사 하강법으로 소프트맥스 회귀를 구현해보세요.(사이킷런 사용 X)

X = iris['data'][:, (2,3)] #Petal Length, Petal Width

y = iris['target']


#모든 샘플에 편향 추가 (x0=1)

#np.c는 R의 cbind와 유사합니다. 즉 column처럼 이어붙입니다. 비슷한 것으로 np.vstack입니다. vertically (수직)

#np.r은 R의 rbind와 유사합니다. 즉, row bind입니다. 비슷한 것은 np.hstack. horizontally 로 이해하시면 됩니다.(수평)

#np.ones는 새로운 Array를 반환하며, 1로 채워집니다. [len(X), 1]은 shape를 나타냅니다. 

#따라서 X, 1 shape의 array와 X array를 columns 형태로 이어붙입니다.

X_with_bias = np.c_[np.ones([len(X), 1]), X]


#결과를 일정하게 유지하기 위해 랜덤시드 고정

np.random.seed(2042)


#데이터셋을 훈련/검증/테스트 Set로 나누는 가장 쉬운 방법은 사이킷런의 train_test_split()

#함수를 사용하는 것입니다. 이 연습문제의 목적은 직접 만들어보면서 알고리즘을 이해하는 것이므로

#다른 방법으로 사용합니다. 아래의 방법은 유사하게 나눌 수 있습니다.


test_ratio=0.2

validation_ratio = 0.2

total_size = len(X_with_bias)


test_size = int(total_size * test_ratio)

validation_size = int(total_size * validation_ratio)

train_size = total_size - test_size - validation_size


#numpy.random.permutation(x)는 무작위로 순서를 바꿉니다. 

#np.random.permutation(10)하면 무작위로 10개의 숫자를 나열한 array가 나옵니다.

#따라서 total_size의 length 길이안에서 섞입니다. 그 섞인 값을 rnd_indices로 지정합니다.


rnd_indices = np.random.permutation(total_size)


#지정된 rnd__indices는 값이 일정하지 않고 마구 섞여있겠죠. 그 안에서 train_size만큼 분할합니다.


X_train = X_with_bias[rnd_indices[:train_size]]

y_train = y[rnd_indices[:train_size]]


#rnd_indices는 이미 지정된 값이기 때문에 계속해서 섞이지 않습니다. 따라서 train_size부터~ test_size까지 나누게 됩니다.


X_valid = X_with_bias[rnd_indices[train_size:-test_size]]

y_valid = y[rnd_indices[train_size:-test_size]]

X_test = X_with_bias[rnd_indices[-test_size:]]

y_test = y[rnd_indices[-test_size:]]


#타깃은 클래스 인덱스(0, 1 그리고 2) 이지만, 소프트맥스 회귀 모델을 훈련시키기 위해 필요한 것은

#타깃 클래스의 확률입니다. 각 샘플에서 확률이 1인 타깃 클래스를 제외한 다른 클래스의 확률은 0

#(다른 말로 주어진 샘플에 대한 클래스 확률이 원-핫 벡터입니다.)


#클래스는 0,1,2이므로 max는 2, 클래스의 개수는 3개이므로 +1

#앞서 봤던 np.ones는 1로 채운다면 zeros는 0으로 채웁니다.

#Y_one_hot은 len_y의 길이만큼의 행, 3개의 열 구조로 생성되고, 모두 0으로만 채워져 있는데,

#np.arange(m), y는 행 열을 선택하게 됩니다.

#행과 열이 모두 0부터 시작하며, iris_target 값이 y이므로 y의 값이 0인경우 첫번째에 1, 

#1인 경우 2번째에 1, 2인경우 3번째 열에 1로 바꿉니다. 

#즉 Y_one_hot은 빈 틀을 만들어 준 셈이고, [ ]를 통해 행 열을 지정하게 됩니다.

#np.arange(m)은 길이가 맞아야 하며 m이 10인 경우 [0,1,2,3,4,5,6,7,8,9]가 생기고,

#                                                      y_train값 [0,1,2,1,1,0,1,1,1,0]이 차례대로 들어갑니다.

#따라서 (0,0)=1, (1,1)=1, (2,2)=1, (3, 1)=1 이런식으로 되어 one-hot 벡터처럼 바꿀 수 있습니다. 


def to_one_hot(y) :

    n_classes = y.max() + 1

    m = len(y)

    Y_one_hot = np.zeros((m, n_classes))

    Y_one_hot[np.arange(m), y] = 1

    return Y_one_hot


#10개의 샘플만 넣어 함수 테스트

y_train[:10]

array([0, 1, 2, 1, 1, 0, 1, 1, 1, 0])

to_one_hot(y_train[:10])

array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.],
       [0., 1., 0.],
       [0., 1., 0.],
       [1., 0., 0.],
       [0., 1., 0.],
       [0., 1., 0.],
       [0., 1., 0.],
       [1., 0., 0.]])

#잘 이해한게 맞네요..

#이제 train, validation, test set 모두 바꿔줍니다.


Y_train_one_hot = to_one_hot(y_train)

Y_valid_one_hot = to_one_hot(y_valid)

Y_test_one_hot = to_one_hot(y_test)


#이제 소프트맥스 함수를 봅니다. (지난 포스팅에서 봄)


[소프트맥스 함수]

s(x) 는 샘플 x에 대한 각 클래스의 점수를 담고 있는 벡터, k는 클래스 수, 

는 샘플 x에 대한 각 클래스의 점수가 주어졌을 때 이 샘플이 클래스 k에 속할 추정 확률


#즉 클래스 k에 속할 추정 확률을 구합니다.


def softmax (logits):

    exps = np.exp(logits)

    exp_sums = np.sum(exps, axis=1, keepdims =True)

    return exps / exp_sums


#이제 입력과 출력의 개수를 정의합니다.


n_inputs = X_train.shape[1] (90,3)[1]  ==3 (특성 2와 편향)

n_outputs = len(np.unique(y_train)) len(array([0,1,2])  ==3 (3개의 붓꽃 클래스)


#이제 비용함수와 그래디언트 공식을 구현합니다.



[크로스 엔트로피 비용 함수]

* i번째 샘플에 대한 타깃 클래스가 k일 때, 가 1이고 그 외에는 0입니다.

* 딱 2개의 클래스가 있을 때 (K=2), 이 비용 함수는 로지스틱 회귀 비용 함수와 같습니다.


[클래스 K에 대한 크로스 엔트로피의 그래디언트 벡터]


** $\hat{p}_k^{(i)} = 0$이면 $\log\left(\hat{p}_k^{(i)}\right)$를 계산할 수 없습니다. nan 값을 피하기 위해 $\log\left(\hat{p}_k^{(i)}\right)$에 아주 작은 값 $\epsilon$을 추가.


# 학습률 0.01,  반복 = 5000
# m = 전체 train set 길이
# 앱실론 = 1e-7 

eta = 0.01

n_iterations = 5001

m = len(X_train)

epsilon = 1e-7


Theta = np.random.randn(n_inputs, n_outputs)


for iteration in range(n_iterations): #5001 -> 0~5000

    logits = X_train.dot(Theta) #(Theta행렬 * X_train행렬)

    Y_proba = softmax(logits) #Y_proba = softmax(logits) => 소프트맥스 함수

    loss = -np.mean(np.sum(Y_train_one_hot * np.log(Y_proba + epsilon), axis=1)) #크로스 엔트로피 비용 함수, epsilon 추가

    error = Y_proba - Y_train_one_hot #클래스 k에 속할 확률과 실제 간 차이

    if iteration % 500 == 0:

        print(iteration, loss)

    gradients = 1/m * X_train.T.dot(error) #클래스 K에 대한 크로스 엔트로피의 그레디언트 벡터

    Theta = Theta - eta * gradients #Theta = Theta - (학습률 * 그레디언트 벡터)


#Theta가 for문을 돌면서 점진적으로 하강하게 됨. 그리고 전체 셋을 사용하고 있으므로 배치 경사하강법.

0 2.0828851886739566 500 0.7785748213387484 1000 0.6476766176998905 1500 0.5697121770727602 2000 0.5182045898073839 2500 0.48105733738538503 3000 0.4524974072153004 3500 0.4295195976924987 4000 0.4104187525819136 4500 0.39415208327581297 5000 0.3800408408828462

Theta

array([[ 3.2208519 , -0.08165991, -3.29989156],
       [-1.18595961, -0.6443119 , -0.37733573],
       [-2.15687546,  0.3408474 ,  1.60127207]])

#검증 세트에 대한 예측과 정확도 확인

#validation(검증 세트)를 사용


logits = X_valid.dot(Theta)

Y_proba = softmax(logits)

y_predict = np.argmax(Y_proba, axis=1)


accuracy_score = np.mean(y_predict == y_valid)

accuracy_score

1.0

#ㄷㄷ 완-벽

#사실 교재에서느느 0.966666정도가 나와서 규제가 들어가야되는데

#완-벽 해서 이거 규제를 해야 되나 싶네요.... 그새 알고리즘이 발전했는지..?.. 뭔지..

#연습을 위해 l2 규제를 가하고, 학습률을 증가시켜봅니다.


#완벽하지만 연습을 위해 l2 규제를 추가해보고, 학습률 증가시켜봅니다.

#손실에 l2 페널티를 추가하고, 그레디언트 항에도 추가합니다.

#Theta의 첫 번째 원소는 편향이므로 규제하지 않습니다.


eta = 0.1

n_iterations = 5001

m = len(X_train)

epsilon = 1e-7

alpha = 0.1  # 규제 하이퍼파라미터


Theta = np.random.randn(n_inputs, n_outputs)


for iteration in range(n_iterations):

    logits = X_train.dot(Theta)

    Y_proba = softmax(logits)


    #numpy.square()는 배열 원소들을 제곱시킵니다.

    xentropy_loss = -np.mean(np.sum(Y_train_one_hot * np.log(Y_proba + epsilon), axis=1))

    l2_loss = 1/2 * np.sum(np.square(Theta[1:]))

    loss = xentropy_loss + alpha * l2_loss

    error = Y_proba - Y_train_one_hot

    if iteration % 500 == 0:

        print(iteration, loss)

    gradients = 1/m * X_train.T.dot(error) + np.r_[np.zeros([1, n_outputs]), alpha * Theta[1:]]

    Theta = Theta - eta * gradients


0 6.113624225870363
500 0.5297190088444882
1000 0.502644547265906
1500 0.4943317904298929
2000 0.49115300862100736
2500 0.4898382545663311
3000 0.48927243978953194
3500 0.48902330313369935
4000 0.4889120552012761
4500 0.4888619344853985
5000 0.48883922237878574

#검증 세트로 확인


logits = X_valid.dot(Theta)

Y_proba = softmax(logits)

y_predict = np.argmax(Y_proba, axis=1)


accuracy_score = np.mean(y_predict == y_valid)

accuracy_score

1.0

# 역시나 모델이 더 좋아질 수 없죠 ?


# 이제 조기 종료를 추가해봅니다. 아마도 조기 종료의 다른 이점도 있지만 5001번 안에 끝날 수도 있겠네요.

# 왜냐하면 값을 보면 알 수 있듯이 2500번부터는 소숫점 3, 4자리수가 변화하고 있습니다.


# 매 반복에서, 검증 세트에 대한 손실을 계산하여 오차가 증가하기 시작할 때, 멈춰야 한다.


eta = 0.1 

n_iterations = 5001

m = len(X_train)

epsilon = 1e-7

alpha = 0.1  # 규제 하이퍼파라미터

best_loss = np.infty


Theta = np.random.randn(n_inputs, n_outputs)


for iteration in range(n_iterations):

    logits = X_train.dot(Theta)

    Y_proba = softmax(logits)

    xentropy_loss = -np.mean(np.sum(Y_train_one_hot * np.log(Y_proba + epsilon), axis=1))

    l2_loss = 1/2 * np.sum(np.square(Theta[1:]))

    loss = xentropy_loss + alpha * l2_loss

    error = Y_proba - Y_train_one_hot

    gradients = 1/m * X_train.T.dot(error) + np.r_[np.zeros([1, n_outputs]), alpha * Theta[1:]]

    Theta = Theta - eta * gradients


# 검증 세트와 같이 계산

    logits = X_valid.dot(Theta)

    Y_proba = softmax(logits)

    xentropy_loss = -np.mean(np.sum(Y_valid_one_hot * np.log(Y_proba + epsilon), axis=1))

    l2_loss = 1/2 * np.sum(np.square(Theta[1:]))

    loss = xentropy_loss + alpha * l2_loss

    if iteration % 500 == 0:

        print(iteration, loss)

    if loss < best_loss:

        best_loss = loss

    else:

        print(iteration - 1, best_loss)

        print(iteration, loss, "early stopping!")

        break


# best_loss를 np.infty라고 하였는데 infty는 inf와 동일한 alias 입니다. 따라서 무한.

# 즉 한없이 큰 수로 지정함 뭐 이거는 왜 이렇게 했는지 모르겠지만 어떤 값도 기록한다는 의미일까요?..

0 1.3104654618363918
500 0.5638848652699527
1000 0.5411567036472769
1500 0.5348667504218284
2000 0.5329992890318709
2500 0.5325642697019287
2670 0.5325458209208133
2671 0.5325458209570282 early stopping!

#아까의 예측대로 2500대 근처에서 멈췄군요. 훨씬 시간을 절약했습니다~~~

#검증

logits = X_valid.dot(Theta)

Y_proba = softmax(logits)

y_predict = np.argmax(Y_proba, axis=1)


accuracy_score = np.mean(y_predict == y_valid)

accuracy_score

1.0



#이제 전체 예측에 대한 그래프를 만들어봅니다. (필수는 아님..)


#전체 예측에 대한 그래프 

#matplotlib 안에 한글을 적용하려면 일시적인 방편으로 포스팅한 것을 보시면 됩니다.

#귀찮다면 직접 영어로 바꾸시길..ㅠㅠ (전 안바꿨어요 나중에 영구적으로 적용하는 방법을 포스팅 하겠습니다.)


x0, x1 = np.meshgrid(

        np.linspace(0, 8, 500).reshape(-1, 1),

        np.linspace(0, 3.5, 200).reshape(-1, 1),

    )

X_new = np.c_[x0.ravel(), x1.ravel()]

X_new_with_bias = np.c_[np.ones([len(X_new), 1]), X_new]


logits = X_new_with_bias.dot(Theta)

Y_proba = softmax(logits)

y_predict = np.argmax(Y_proba, axis=1)


zz1 = Y_proba[:, 1].reshape(x0.shape)

zz = y_predict.reshape(x0.shape)


plt.figure(figsize=(10, 4))

plt.plot(X[y==2, 0], X[y==2, 1], "g^", label="Iris-Virginica")

plt.plot(X[y==1, 0], X[y==1, 1], "bs", label="Iris-Versicolor")

plt.plot(X[y==0, 0], X[y==0, 1], "yo", label="Iris-Setosa")


from matplotlib.colors import ListedColormap

custom_cmap = ListedColormap(['#fafab0','#9898ff','#a0faa0'])


plt.contourf(x0, x1, zz, cmap=custom_cmap)

contour = plt.contour(x0, x1, zz1, cmap=plt.cm.brg)

plt.clabel(contour, inline=1, fontsize=12)

plt.xlabel("꽃잎 길이", fontsize=14)

plt.ylabel("꽃잎 폭", fontsize=14)

plt.legend(loc="upper left", fontsize=14)

plt.axis([0, 7, 0, 3.5])

plt.show()



마지막으로 테스트 셋에 적용해서 마무리합니다.


logits = X_test.dot(Theta)

Y_proba = softmax(logits)

y_predict = np.argmax(Y_proba, axis=1)


accuracy_score = np.mean(y_predict == y_test)

accuracy_score

0.9333333333333333

최종 모델의 성능이 조금 떨어졌지만 데이터셋이 작아서라고 합니다. 

저자는 훈련 세트와 검증 세트, 테스트 세트를 어떻게 샘플링 하냐에 따라 결과가 달라질 수 있으므로, 랜덤 시드를 바꾸면서 해보면 달라질 것이라고 합니다.


하지만 뭐 93.3%도 매우 높다고 생각되네요.

6.7%는 변종일까 궁금하네요


다음 포스팅은 5장 서포트 벡터머신의 심화과정을 포스팅하겠습니다!


 블로그 

출처


이 글의 상당 부분은  [핸즈온 머신러닝, 한빛미디어/오렐리앙 제롱/박해선] 서적을 참고하였습니다.


나머지는 부수적인 함수나 메서드에 대해 부족한 설명을 적어두었습니다.

학습용으로 포스팅 하는 것이기 때문에 복제보다는 머신러닝에 관심이 있다면 구매해보시길 추천합니다.


도움이 되셨다면 로그인 없이 가능한

아래 하트♥공감 버튼을 꾹 눌러주세요! 



반응형