머신 러닝 알고리즘은 크게 지도학습과 비지도학습, 강화학습으로 구분된다.
① 지도학습
② 비지도학습
③ 강화학습
지난 시간에는 머신 러닝 모델을 훈련할 때 사용한 데이터를 그대로 이용하여 성능 평가를 진행하였더니 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이 나올 것이다.
정확도가 0.0이 나온 이유는 훈련 Set과 테스트 Set 안에 도미와 빙어 데이터가 골고루 섞여 있지 않았기 때문이다. 즉, 샘플링 편향이 발생했기 때문이다. 당연히 훈련 Set 안에는 도미 밖에 없고, 테스트 Set 안에는 빙어 밖에 없으니 정답을 맞히지 못하는 것이다.
하지만 막상, 도미와 빙어 데이터를 골고루 섞어보면, 생각보다 번거로운 일이라는 것을 알게 될 것이다. 그러므로 지금부터, 배열을 손쉽게 생성 및 조작하는 Numpy 라이브러리에 대해 배워보기로 하자.
Numpy는 파이썬의 대표적인 배열 라이브러리이다. Numpy를 사용하면, 2차원 리스트뿐 아니라, 고차원의 리스트도 손쉽게 조작할 수 있게 된다.
① 모듈 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번 인덱스의 원소 선택
Sample을 랜덤하게 선택하여 훈련 Set과 테스트 Set을 나누는 방법은 크게 두 가지이다.
여기서는 두번째 방법을 사용할 것이다. 이 때, 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:]]
③ 산점도 그리기
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()
④ 산점도 분석
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()
① 모델 훈련하기
kn.fit(train_input, train_target)
② 모델 성능 평가
kn.score(test_input, test_target)
샘플링 편향을 방지하고, 훈련 Set과 테스트 Set을 구분함으로써 보다 정확한 모델 성능 평가가 가능해졌다.