본문 바로가기
인공지능/혼자 공부하는 머신러닝 + 딥러닝

02-1 훈련 세트와 테스트 세트

by 녤 2023. 2. 3.

책 66p. ~ 83p.

 

1. 테스트 세트가 필요한 이유

 

-K최근접 이웃 알고리즘: 규칙을 찾기 보단, 단순히 훈련 데이터를 저장한 후 가까운 이웃을 골라서 다수인 클래스를 예측 클래스로 삼는 알고리즘 

 

-fit() 메서드를 사용하여 훈련할 때, 사용했던 데이터를 그대로 사용하면 머신러닝 모델이 이미 정답을 알고 있으므로 정확도가 100%가 나오는 것이 당연함 

→ 새로운 데이터를 사용해야 올바른 정확도를 알 수 있을 것 

 

 

2. 지도 학습과 비지도 학습 

 

지도 학습: 데이터 입력 시에 정답(타깃) 데이터도 함께 입력 → 머신러닝 모델에게 정답을 가르침

ex) 입력된 데이터가 도미인지 빙어인지를 구분

 

비지도 학습: 데이터 입력 시에 타깃 데이터 없이 데이터'만' 입력 → 정답을 사용하지 않으므로 무언가를 맞출 수 없음 BUT 특성 개수를 낮추거나 비슷한 샘플 모으기 등의 작업을 진행

 

강화 학습: 모델이 어떤 행동을 수행하면 주변 환경에서 보상을 얻음, 보상을 얻을 수 있는 쪽으로 학습을 진행하는 것

 

입력(input): 지도 학습에서 머신 러닝 모델에게 훈련 시키는 '데이터'

타깃(target): 지도 학습에서 머신러닝 모델에게 알려주는 '정답'

 

특성: 입력으로 사용된 데이터의 '특징'

ex) 해당 머신러닝 알고리즘 '도미와 빙어 구분하기'에서는 생선의 '길이' 와 '무게'를 특성으로 사용하였다. 

 

=> K 최근접 이웃 알고리즘은 지도 학습에 해당하는 머신러닝 알고리즘 

 

 

3. 알고리즘의 성능 평가

 

-머신러닝의 알고리즘의 성능을 제대로 평가하기 위해서는 훈련 데이터와 평가에 사용할 데이터가 각각 달라야 함  

 

-훈련에 사용한 데이터로 모델의 성능을 평가하는 것은 정답지 외우고 시험을 보는 것과 같음!

 

~훈련 데이터와 테스트 데이터를 나누는 방법~

 

1. 평가를 위해 또 다른 데이터를 준비하기

2. 이미 준비된 데이터 중에 일부를 떼어내서 테스트 데이터로 사용하기  → 일반적으로 2번을 많이 사용

 

테스트 세트: 평가에 사용하는 데이터

훈련 세트: 훈련에 사용되는 데이터

 

훈련 데이터 (세트) = 테스트 세트 + 훈련 세트 

 

 

<빙어와 도미 데이터 준비하기>

fish_length = [25.4, 26.3, 26.5, 29.0, 29.0, 29.7, 29.7, 30.0, 30.0, 30.7, 31.0, 31.0, 
                31.5, 32.0, 32.0, 32.0, 33.0, 33.0, 33.5, 33.5, 34.0, 34.0, 34.5, 35.0, 
                35.0, 35.0, 35.0, 36.0, 36.0, 37.0, 38.5, 38.5, 39.5, 41.0, 41.0, 9.8, 
                10.5, 10.6, 11.0, 11.2, 11.3, 11.8, 11.8, 12.0, 12.2, 12.4, 13.0, 14.3, 15.0]
fish_weight = [242.0, 290.0, 340.0, 363.0, 430.0, 450.0, 500.0, 390.0, 450.0, 500.0, 475.0, 500.0, 
                500.0, 340.0, 600.0, 600.0, 700.0, 700.0, 610.0, 650.0, 575.0, 685.0, 620.0, 680.0, 
                700.0, 725.0, 720.0, 714.0, 850.0, 1000.0, 920.0, 955.0, 925.0, 975.0, 950.0, 6.7, 
                7.5, 7.0, 9.7, 9.8, 8.7, 10.0, 9.9, 9.8, 12.2, 13.4, 12.2, 19.7, 19.9]


fish_data = [[l, w] for l, w in zip(fish_length, fish_weight)]
fish_target = [1]*35 + [0]*14

 

샘플: 하나의 데이터 → 도미와 빙어 구분하는 머신러닝 알고리즘에서의 샘플 = 하나의 생선 데이터

 

도미 35마리, 빙어 14마리로 총 49개의 샘플이 있으며 사용하는 특성은 길이와 무게 두 가지이다. 따라서 길이와 무게 리스트의 개수는 각각 49개

 

이 중 35개는 훈련 데이터, 14개는 테스트 데이터로 활용

 

<도미와 빙어 구분 알고리즘 훈련 및 성능 평가하기>

from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()

#훈련 세트로 입력값 중 0번 부터 34번 인덱스까지를 사용
train_input = fish_data[:35]

#훈련 세트로 타깃(정답)값 중 0부터 34번 인덱스까지를 사용
train_target = fish_target[:35]

#테스트 세트로 입력값 중 35번 인덱스부터 마지막 인덱스까지를 사용
test_input = fish_data[35:]

#테스트 세트로 타깃값 중 35번 인덱스부터 마지막 인덱스까지를 사용
test_target = fish_target[35:]

데이터를 나눌 때는 슬라이싱 연산자를 활용한다. 

 

*슬라이싱은 마지막 인덱스를 포함하지 않는다. 즉 [0:35]이면 0~34까지 35개의 원소만 선택되고, 36번째 원소인 35번 인덱스는 선택되지 않음

 

**처음부터 시작되는 슬라이싱의 경우 0을 생략하고 사용하는 것이 가능하며, 이와 같이 마지막 원소까지 포함할 경우 마지막 인덱스를 생략하는 것이 가능하다

 a = [1, 2, 3, 4, 5, 6, 7]

a[:5] #인덱스 0~4까지 5개의 원소를 선택함
a[1:] #인덱스 1부터 마지막까지 5개의 원소를 선택함

 

score 함수의 결과를 확인해보면

kn.fit(train_input, train_target)
kn.score(test_input, test_target)

정확도가 0인 것을 확인할 수 있다. 

 

 

4. 샘플링 편향

 

정확도가 0인 이유 : 데이터를 만들 때 앞의 35는 도미, 뒤의 14개는 빙어로 만들었기 때문에 훈련 데이터에는 도미 데이터만, 테스트 세트에는 빙어 데이터만 들어가게 됨 

 

→ 훈련 세트에는 도민만 있기 때문에 테스트 세트가 무엇이든 무조건 도미라고 분류함. 그렇지만 테스트 세트는 빙어만 있기 때문에 정답을 맞추지 못한 것!

 

샘플링 편향: 훈련 세트와 테스트 세트가 골고루 섞여 있지 않는 현상. 특정 종류의 샘플이 과도하게 많은 샘플링 편향을 가지고 있으면 제대로 된 지도 학습 모델을 만들 수 없음 

 

 

5. 넘파이 기본

 

-파이썬의 대표적인 배열 라이브러리, 고차원의 배열을 손쉽게 만들고 조작할 수 있는 간편한 도구들을 제공 

 

ex) 사이킷런의 predict() 메서드 → 넘파이 배열로 값을 반환... 입력값도 넘파이 배열로 가정한다. 

; 우리가 predict() 메서드를 사용할 때 2차원 리스트로 넘긴 것을 넘파이 배열로 변환하고 처리하기 때문 

 

~ 차원 정리 ~

 

차원1 : 축의 개수(1차원, 2차원(x, y), 3차원(x, y, z))

차원2 : 벡터에서의 원소의 개수 

 

<넘파이 사용해보기>

 

import numpy as np

#array()함수에 파이썬 리스트를 전달하면 리스트가 넘파이 배열로 바뀐다
input_arr = np.array(fish_data)
target_arr = np.array(fish_target)

print(input_arr)

#shape함수는 (샘플 수, 특성 수)를 출력한다
print(input_arr.shape)

shpae()함수를 통해 넘파이 배열의 크기를 확인할 수 있다. 49개의 샘플과 2개의 특성이 있음을 알 수 있다. 

 

 

6. 넘파이 shuffle

 

-데이터를 랜덤하게 섞을 때는 입력 데이터와 타깃 데이터에서 같은 위치가 함께 선택되어야 한다. → 타깃이 샘플과 함께 이동하지 않으면 올바르게 훈련될 수 없기 때문

; 당연함. 입력의 [0]번째 데이터가 도미인데 타깃의 [0]번째 데이터의 값이 빙어이면 완전 다르게 훈련하는 것

 

=> 훈련 세트와 테스트 세트로 나눌 인덱스 값을 잘 기억해야 함!

 

np.random.seed(42) #책과 일정한 결과를 얻기 위해 시드를 42로 설정
index = np.arange(49) #넘파이 arrange()를 사용하여 0부터 48까지 1씩 증가하는 배열을 생성
print(index)

* 넘파이 arange()함수에 정수 N을 전달하면 0에서부터 N-1까지 1씩 증가하는 배열을 만들 수 있음 

 

np.random.shuffle(index) #index 배열을 shuffle()에 넣어 배열을 무작위로 섞음 
print(index)

 

 

7. 배열 인덱싱

 

배열 인덱싱: 1개의 인덱스가 아닌 여러 개의 인덱스로 한 번에 여러 원소를 선택하는 것. 넘파이 배열 역시 인덱스로서 사용이 가능하다. 

 

사용 예시) 

 

즉, 배열 인덱스에 다른 배열을 넣어서, 배열의 원소를 선택하는 방법을 의미한다. 

 

앞에서 만든 index 배열(특: 섞여 있음) 을 input_arr과 target_arr의 인덱스로 사용하여 랜덤한 35개의 샘플을 훈련 세트로,랜덤한 14개의 샘플을 테스트 세트로 만들 것!

 

#훈련 데이터의 입력값으로 넘파이 배열의 0~34번째 인덱스의 값을 넣음 
train_input = input_arr[index[:35]] 
#현재 0번 인덱스 = 13번 인덱스이므로 train_input[0]에 있는 데이터는 input_arr[13]에 있는 데이터
print(input_arr[13], train_input[0])

#훈련 데이터의 타깃값으로 넘파이 배열의 0~34번째 인덱스의 값을 넣음 
train_target = target_arr[index[:35]] 

test_input = input_arr[index[35:]]
test_target = target_arr[index[35:]]

input_arr의 13번째 값과 trai_input의 0번째 값이 같은 것을 확인할 수 있다.

 

 

8. 산점도로 데이터가 잘 섞였는지 확인하기 

 

import matplotlib.pyplot as plt

#훈련 데이터 산점도 표시
plt.scatter(train_input[:, 0], train_input[:, 1])

#테스트 데이터 산점도 표시
plt.scatter(test_input[:, 0], test_input[:, 1])
plt.xlabel('lenght')
plt.ylabel('weight')
plt.show()

 

- 2차원 배열은 행과 열 인덱스를 콤마( , )로 나누어서 지정함. 만약 슬라이싱 연산자로 처음부터 마지막 원소까지 모두 선택하는 경우 시작과 종료 인덱스를 모두 생략하는 것이 가능

 

9. 모델 다시 훈련 하기 

 

- fit() 메서드를 실행할 때 마다, KNeighbotsClassifier 클래스의 객체는 이전에 학습한 모든 것을 잃어버림 → 이전에 학습한 모델을 그대로 두고 싶다면 새 객체를 만들어서 사용 

 

kn.fit(train_input, train_target)
kn.score(test_input, test_target)

스코어가 1.0으로 정확도 100%가 나온 것을 확인할 수 있다. 

 

kn.predict(test_input)

predict 메서드로 test_input의 값을 예측했다. 

 

test_taget의 값과 같은 것을 확인할 수 있다.