Training Set과 Test Set

변현섭·2024년 6월 28일
0
post-thumbnail

1. 용어 정리

1) 지도학습과 비지도학습

머신 러닝 알고리즘은 크게 지도학습과 비지도학습, 강화학습으로 구분된다.

① 지도학습

  • 훈련을 위한 데이터 Set이 필요하며, 이를 훈련 데이터라고 부른다.
  • 훈련 데이터는 특성 데이터 Set과 정답 데이터 Set으로 구분되는데, 이를 각각 Input과 Target이라 부른다.
  • 이전 시간에 배운 KNN 알고리즘이 지도학습에 속한다.

② 비지도학습

  • Target 없이 Input만 사용하는 알고리즘이다.
  • 데이터의 구조를 이해하고 숨겨진 규칙성을 찾아내는 것을 목표로 한다.

③ 강화학습

  • 어떤 환경 안에서 정의된 Agent(학습을 수행하는 주체)가 현재의 선택 가능한 행동들 중, 특정 목표를 달성하기 위한 최적의 행동을 학습하는 방법론이다.

2) 훈련 Set과 테스트 Set

지난 시간에는 머신 러닝 모델을 훈련할 때 사용한 데이터를 그대로 이용하여 성능 평가를 진행하였더니 score가 1.0이 나왔다. 하지만, 이는 정확한 성능 평가로 볼 수 없다.

마치 문제와 답을 다 알려준 후에, 문제를 똑같이 내서 100점을 맞은 학생을 똑똑하다고 평가하기 어려운 이치와 같다. 즉, 모델의 정확한 성능 평가를 진행하기 위해서는 훈련 Set과 구별되는, 별도의 테스트 Set이 존재해야 한다.

훈련 Set과 테스트 Set을 구분하는 가장 쉬운 방법은 주어진 특성 데이터 중 일부는 훈련 Set으로, 나머지는 테스트 Set으로 사용하는 것이다. 아래와 같이 특성 데이터 Set이 주어졌다고 하자.

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]

지난 시간에 배운대로 먼저는 데이터를 2차원 배열로 변환하고, 정답 데이터 Set을 만들어주어야 한다.

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

이 때, fish_data의 각 원소(1차원 배열)를 Sample이라고 부른다. 이제 파이썬의 슬라이싱 연산을 이용해 49개의 샘플 중 첫 35개는 훈련 Set으로, 나머지 14개는 테스트 Set으로 사용할 것이다.

## 훈련 Set ##
train_input = fish_data[:35]
train_target = fish_target[:35]

## 테스트 Set ##
test_input = fish_data[35:]
test_target = fish_target[35:]

코드 셀에 아래의 내용을 입력한 후 실행해보자. (Alt + Enter로 실행 및 다음 코드 셀 추가 가능)

from sklearn.neighbors import KNeighborsClassifier

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

train_input = fish_data[:35]
train_target = fish_target[:35]

test_input = fish_data[35:]
test_target = fish_target[35:]

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

성능 평가 결과로 0.0이 나올 것이다.

3) 샘플링 편향

정확도가 0.0이 나온 이유는 훈련 Set과 테스트 Set 안에 도미와 빙어 데이터가 골고루 섞여 있지 않았기 때문이다. 즉, 샘플링 편향이 발생했기 때문이다. 당연히 훈련 Set 안에는 도미 밖에 없고, 테스트 Set 안에는 빙어 밖에 없으니 정답을 맞히지 못하는 것이다.

하지만 막상, 도미와 빙어 데이터를 골고루 섞어보면, 생각보다 번거로운 일이라는 것을 알게 될 것이다. 그러므로 지금부터, 배열을 손쉽게 생성 및 조작하는 Numpy 라이브러리에 대해 배워보기로 하자.

2. Numpy

Numpy는 파이썬의 대표적인 배열 라이브러리이다. Numpy를 사용하면, 2차원 리스트뿐 아니라, 고차원의 리스트도 손쉽게 조작할 수 있게 된다.

1) 기본 사용법

① 모듈 import

import numpy as np

② List를 Numpy 배열로 변환

np_fish_data = np.array(fish_data)
np_fish_target = np.array(fish_target)
  • Numpy 배열은 2차원 List의 차원을 구분하여 출력하기 때문에 데이터 확인이 보다 용이하다.

    • 파이썬 List

    • Numpy 배열

③ 행(Sample)과 열(Features)의 개수 알아내기

print(np_fish_data.shape) # (49, 2) 출력

④ 배열 인덱싱

  • 여러 개의 인덱스를 이용해 한번에 여러 개의 원소를 선택할 수 있다.
print(np_fish_data[[1, 3]]) # 1, 3번 인덱스의 원소 선택

2) 훈련 Set과 테스트 Set 만들기

Sample을 랜덤하게 선택하여 훈련 Set과 테스트 Set을 나누는 방법은 크게 두 가지이다.

  • 배열을 랜덤하게 섞은 후 슬라이싱 연산으로 구분
  • 각 Set에 들어갈 Sample을 랜덤하게 선택

여기서는 두번째 방법을 사용할 것이다. 이 때, np_fish_data와 np_fish_target에서 한 Sample은 동일한 Index를 공유한다는 점을 이용하면, Index를 랜덤 선택하는 방식으로 Sample을 랜덤하게 선택하는 효과를 낼 수 있다. 이 내용을 바탕으로 훈련 Set과 테스트 Set 만들어보자.

① Index 랜덤 선택

np.random.seed(42) # 일정한 결과를 얻기 위해 Seed를 지정한 것뿐이므로, 실전에서는 사용할 필요 없음
index = np.arange(49) # 0 ~ 48까지 1씩 증가하는 배열 생성
np.random.shuffle(index) # 배열을 무작위로 섞음

② 훈련 Set과 테스트 Set 구성

## 훈련 Set ##
train_input = np_fish_data[index[:35]]
train_target = np_fish_target[index[:35]]

## 테스트 Set ##
test_input = np_fish_data[index[35:]]
test_target = np_fish_target[index[35:]]

③ 산점도 그리기

  • 도미 데이터와 빙어 데이터가 골고루 섞였는지 분석하기 위해, 훈련 Set과 테스트 Set의 산점도를 그린다.
import matplotlib.pyplot as plt

plt.scatter(train_input[:, 0], train_input[:, 1]) # x축에는 모든 Sample의 length를, y축에는 모든 Sample의 weight를 전달
plt.scatter(test_input[:, 0], test_input[:, 1])
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

④ 산점도 분석

  • 훈련 Set과 테스트 Set에 도미 데이터와 빙어 데이터가 골고루 잘 섞였음을 확인할 수 있다.
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
import numpy as np

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

np_fish_data = np.array(fish_data)
np_fish_target = np.array(fish_target)

np.random.seed(42) 
index = np.arange(49) 
np.random.shuffle(index) 

## 훈련 Set ##
train_input = np_fish_data[index[:35]]
train_target = np_fish_target[index[:35]]
## 테스트 Set ##
test_input = np_fish_data[index[35:]]
test_target = np_fish_target[index[35:]]

plt.scatter(train_input[:, 0], train_input[:, 1]) 
plt.scatter(test_input[:, 0], test_input[:, 1])
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

3. 모델 성능 평가

① 모델 훈련하기

  • 참고로, fit 메서드를 실행할 때마다 KNeighborsClassifier의 객체는 이전에 학습한 모든 내용을 잃게 된다.
kn.fit(train_input, train_target)

② 모델 성능 평가

kn.score(test_input, test_target)

샘플링 편향을 방지하고, 훈련 Set과 테스트 Set을 구분함으로써 보다 정확한 모델 성능 평가가 가능해졌다.

profile
LG전자 Connected Service 1 Unit 연구원 변현섭입니다.

0개의 댓글