지난 시간에 Pupbani는 K-최근접 이웃 알고리즘으로 머신러닝 모델을 만들어 생선을 분류하는 프로그램을 만들었다.
이에 대한 보고서를 작성해 박팀장에게 전달해 보았다.
보고서를 보고 이상한지 박팀장이 다음과 같이 말하였다.
"도미 35마리와 14마리를 모두 저장하고 맞추는 거라면 100%를 달성하는게 당연하지 않나요? 어떤 것이 도미이고 빙어인지 알고 있는데 맞추지 못하는 것이 이상한거 같은데..."
Pupbani는 이전에 배웠던 머신러닝의 기초부터 다시 곱씹어보면서 이 문제를 해결하기로 결정했다.
머신러닝의 학습 종류
지도학습(Supervised Learning)
- 데이터와 데이터에 대한 정답이 필요하다.
- 이전에 사용했던 KNeighborsClassifier도 지도학습 모델이다.
- 데이터 : 생선의 길이와 무게
- 정답 : 생선 종류
- 지도학습에서는 데이터를 입력(input)이라하고 정답을 타깃(Target)이라하고 묶어서 훈련 데이터(Training Data)라고 부른다.
- 이전 글에서 언급했듯이 입력으로 사용된 길이와 무게를 특성(Feature)라고 한다.
- 지도학습은 정답을 알고 있으니 알고리즘이 정답을 맞추는 것을 학습한다.
비지도학습(Unsupervised Learning)
- 타깃 없이 입력 데이터만 사용한다.
- 정답을 모르는 상태로 학습하므로 무언가를 맞추는 일을 할 수 없다.
- 데이터를 잘 파악하거나 변형하는 데 도움을 준다.
강화학습(Reinforcement Learning)
- 알고리즘이 행동한 결과로 얻은 보상(Reward)를 사용해 학습을 진행한다.
- 학습 방향은 행동에 대한 보상이 큰 쪽으로 학습을 진행한다.
데이터 세트의 종류
우리가 학교에서 시험 공부를 할 때 시험에 나올 문제를 미리 알려주고 시험을 본다면 어떨까?
- 문제와 정답을 외우고 시험을 본다면 100점을 맞을 수 있다.
머신러닝도 이와 마찬가지 이다.
도미와 빙어의 데이터와 타깃으로 학습 후 학습에 사용한 데이터로 평가를 하면 모두 맞히는 것이 당연하다.
연습 문제와 시험 문제가 달라야 올바르게 학생의 능력을 평가할 수 있듯이 머신러닝에서도 성능 평가를 위해서 훈련 데이터와 평가에 사용할 데이터가 달라야한다.
훈련 세트(Traning Set)
- 모델 훈련에 사용하는 데이터 세트
테스트 세트(Test 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차원 리스트를 만든다.
fish_data = [[l, w] for l, w in zip(fish_length,fish_weight)]
fish_target = [1] * 35 + [0] * 14
이 때 만들어진 하나의 생선 데이터([길이, 무게]) 데이터를 샘플(Sample)이라고 한다.
총 49개의 생선 데이터가 있으므로 샘플은 총 49개 이다.
이 중 35개를 훈련 세트로 14개를 테스트 세트로 사용하겠다.
파이썬의 리스트 슬라이싱(slicing)을 통해 훈련 세트와 테스트 세트를 나눠보겠다.
- :(콜론)을 가운데에 두고 인덱스의 범위를 지정하여 여러개의 원소들을 선택할 수 있다.
- 마지막 인덱스는 포함되지 않는다. --> Ex) l[0:5] // 0~4까지
- start 부분을 생략하면 0부터 시작한다. --> Ex) l[:5] // 0~4까지
- end 부분을 생략하면 리스트의 끝까지 포함한다. --> Ex) l[2:] // 2~리스트의 끝까지
- step의 값(기본값=1)에 따라 다음 값이 정해진다. --> Ex) l[1:5:2] // 1부터 2씩 증가 4까지, [1,3]
예시 test_list = [1,2,3,4,5,6,7,8,9,10]
print(test_list[1:5])
// start 생략
print(test_list[:5])
// end 생략
print(test_list[2:])
// step
print(test_list[10::-1])
이 슬라이싱으로 데이터를 훈련 세트와 테스트 세트로 나누어 보겠다.
train_input = fish_data[:35] // 훈련 세트 입력
train_target = fish_target[:35] // 훈련 세트 타겟
test_input = fish_data[35:] // 테스트 세트 입력
test_target = fish_target[35:] // 테스트 세트 타겟
이제 이 데이터 세트를 가지고 학습을 진행하고 평가를 해보 겠다.
kn = kn.fit(train_input, train_target)
print(f"훈련 결과 : {kn.score(test_input, test_target) * 100}%")
정확도가 0%가 나왔다. 무엇이 문제일까?
샘플링 편향(Sampling bias)
정확도가 0%가 나온 모니터를 보고 고민하고 있던 중 지나가 던 김선배가 한마디를 건냈다.
- "훈련 세트와 테스트 세트를 나눌때 전체 데이터에서 마지막 14개만 떼어서 만들면 훈련 세트에는 빙어에 대한 데이터가 하나도 들어있지 않잖아요... 빙어 없이 모델을 훈련했으니 빙어를 올바르게 구분 할 수 없죠..."
- "훈련 세트와 테스트 세트를 나눌때는 골고루 섞이게 만들어야 해요."
테스트 세트에 샘플이 골고루 섞여 있지 않으면 샘플링 한쪽으로 치우쳤다는 의미로 샘플링 편향(Sampling bias)이라고 부른다.
이제 Pupbani는 도미와 빙어를 적절히 섞어서 훈련 세트와 테스트 세트를 만들어야한다.
이러한 작업을 간편하게 처리할 수 있도록 파이썬에서는 Numpy라는 라이브러리를 지원한다.
Numpy를 사용해서 올바른 훈련 데이터를 만들어 보자.
넘파이(Numpy)
- 파이썬의 대표적인 배열(Array) 라이브러리 이다.
- 파이썬의 리스트는 고차원의 리스트를 표현하기에는 매우 번거롭다.
- 넘파이는 고차원 배열 생성, 조작을 쉽게 할 수 있는 간편한 도구를 많이 제공한다.
넘파이 사용(import)
- 보통 넘파이는 np로 별명을 붙여서 사용한다.
import numpy as np
리스트를 넘파이 배열로 바꾸기
- array() 함수에 매개변수로 리스트를 전달하면 된다.
- Numpy 배열은 슬라이싱을 지원한다.
input_arr = np.array(fish_data) // 훈련 데이터
target_arr = np.array(fish_target) // 타겟 데이터
print(input_arr[:5]) // 0~4번 인덱스까지
배열의 크기를 알아보기
- shape 속성을 통해 배열의 크기를 알 수 있다.
- 이 명령을 통해 (세로축 길이, 가로축 길이)를 출력한다.
print(input_arr.shape)
데이터 섞기
- 샘플 데이터와 타겟 데이터에서 같은 위치는 함께 선택 되어야 한다.
- Ex) 샘플 데이터의 1번 값은 훈련 세트로, 타겟 데이터의 1번 값은 테스트 세트로 가면 안된다.
- 타겟이 샘플과 함께 이동하지 않으면 올바른 훈련이 될 수 없다.
- 그러므로 훈련 세트와 테스트 세트로 나눌 인덱스 값을 잘 기억해야 한다.
- 하지만 매번 이렇게 기억할 수 없으니 다른 방법이 필요하다.
- 인덱스를 섞은 다음 샘플을 선택하면 무작위로 훈련 세트를 나누는 셈이 된다.
- arange() 함수를 사용해 0~48까지 1씩 증가하는 인덱스르 쉽게 만들 수 있다.
- 인덱스를 섞어 보자 - random 패키지
- seed() : 절달된 매개변수 값을 시드(난수 수열의 시작 수)로 설정한다.
- shuffle() : 주어진 배열을 무작위 섞는다.
np.random.seed(42)
index = np.arange(49) // 0~48까지 1씩 증가하는 array 배열 생성
np.random.shuffle(index) // 섞기
print(index)
- Numpy는 배열 인덱싱(Array Indexing)을 지원한다.
- 1개의 인덱스가 아닌 여러개의 인덱스로 한 번에 여러 개의 원소를 선택할 수 있다.
- 이 방법을 사용해 위에서 만들어둔 랜덤한 인덱스를 전달하여 잘 섞인 데이터를 생성한다.
print(input_arr[[1,3]]) // input_arr의 1~2번 인덱스의 값
// 훈련 세트
// index의 시작 값 부터 34번째 값까지 Array indexing
train_input = input_arr[index[:35]]
train_target = target_arr[index[:35]]
// 테스트 세트
// index의 35번째 값 부터 끝 까지 Array indexing
test_input = input_arr[index[35:]]
test_target = target_arr[index[35:]]
- 이렇게 만들어진 데이터들이 잘 섞여 있는지 시각화하여 확인해 본다.
- 2차원 배열은 행과 열 인덱스를 ,(콤마)로 나누어 지정한다.
- 슬라이싱 연산자로 처음~끝까지 모두 선택할 경우 시작, 종료 인덱스를 생략 가능하다.
import matplotlib.pyplot as plt
plt.scatter(train_input[:, 0], train_input[:, 1]) // 0: 길이, 1: 무게
plt.scatter(test_input[:, 0], test_input[:, 1]) // 0: 길이, 1: 무게
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
- 훈련 데이터가 잘 섞인 것 같다.
- 이제 이 데이터를 가지고 새로운 머신러닝 프로그램을 만들어 보자.
두 번째 머신러닝 프로그램
이제 앞에 만든 데이터들로 KNeighborClassifier 모델을 학습 시켜 테스트 해보겠다.
모델 생성
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
모델 훈련
kn.fit(train_input, train_target)
모델 평가
print(f"훈련 결과 : {kn.score(test_input, test_target) * 100}%")
예측
prd = kn.predict(test_input)
kind = {0:"빙어",1:"도미"}
print(f"예측 : {[kind[i] for i in prd]}")
print(f"정답 : {[kind[i] for i in test_target]}")
모델이 예측한 결과와 정답이 전부 같다.
이번에는 모델을 훈련할 때 들어 있지 않은 샘플로 테스트를 했기 때문에 올바르게 평가했다.
이제 결과를 보고하러 가보자.
'AI > 기계학습(Machine Learning)' 카테고리의 다른 글
[기계학습/ML]6. 회귀 알고리즘(1) - K-최근접 이웃 회귀, 선형회귀 (0) | 2022.10.23 |
---|---|
[기계학습/ML]5. 데이터 전처리 - 표준점수, 브로드캐스팅 (0) | 2022.10.22 |
[기계학습/ML]3. 머신러닝 맛보기 - K-NeighborsClassifier(K-최근접 이웃 분류) (0) | 2022.10.22 |
[기계학습/ML]2. 실습 환경 - Colab Notebooks (0) | 2022.10.22 |
[기계학습/ML]1. 개요 - 인공지능, 머신러닝, 딥러닝 (0) | 2022.10.21 |