<혼자 공부하는 머신러닝 + 딥러닝>의 'Ch.2 데이터 다루기_1. 훈련 세트와 테스트 세트'의 내용을 요약 및 정리한 내용입니다.
https://product.kyobobook.co.kr/detail/S000001810330
혼자 공부하는 머신러닝+딥러닝 | 박해선 - 교보문고
혼자 공부하는 머신러닝+딥러닝 | 혼자 해도 충분하다! 1:1 과외하듯 배우는 인공지능 자습서이 책은 수식과 이론으로 중무장한 머신러닝, 딥러닝 책에 지친 ‘독학하는 입문자’가 ‘꼭 필요한
product.kyobobook.co.kr
1. 지도 학습과 비지도 학습의 차이를 배웁니다.
2. 모델을 훈련시키는 훈련 세트와 모델을 평가하기 위한 테스트 세트로 데이터를 나눠서 학습해 봅니다.
1. 지도 학습과 비지도 학습
머신러닝 알고리즘은 크게 지도 학습과 비지도 학습으로 나눌 수 있습니다.
지도 학습 알고리즘은 훈련하기 위한 데이터와 정답이 필요합니다.
만약에 도미와 빙어 데이터를 통해 분류한다고 해보겠습니다. 그렇다면 생선의 길이와 무게를 알고리즘에 사용합니다. 이 경우 정답은 도미인지 아닌지 여부입니다.
이때, 지도 학습에서는 데이터와 정답을 입력과 타깃이라고 하고, 이 둘을 합쳐 훈련데이터라고 부릅니다. 또한 입력으로 사용된 길이와 무게를 특성이라고 합니다. 위의 경우, 도미와 빙어를 구분하는데 사용한 길이와 무게가 특성에 해당합니다.
지도 학습은 정답(타깃)이 있으니 알고리즘이 정답을 맞히는 것을 학습합니다. 예를 들어 도미인지 빙어인지 구분하는 것이 이에 해당합니다.
반면 비지도 학습 알고리즘은 타깃 없이 입력 데이터만 사용합니다. 이런 종류의 알고리즘은 정답을 사용하지 않으므로 무언가를 맞힐 수가 없습니다. 대신 데이터를 잘 파악하거나 변형하는 데 도움을 줍니다.
2. 훈련 세트와 테스트 세트
만약 시험을 보기 전에 출제될 시험 문제와 정답을 알려주고 시험을 본다면, 단지 정답을 외우는 것만으로 100점을 맞을 것입니다. 머신러닝도 이와 마찬가지입니다. 도미와 빙어의 데이터와 타깃을 주고 훈련한 다음, 같은 데이터로 테스트한다면 모두 맞히는 것이 당연합니다.
연습 문제와 시험 문제가 달라야 올바르게 학생의 능력을 평가할 수 있듯이 머신러닝 알고리즘의 성능을 제대로 평가하려면 훈련 데이터와 평가에 사용할 데이터가 각각 달라야 합니다.
이렇게 하는 가장 간단한 방법은 평가를 위해 또 다른 데이터를 준비하거나 이미 준비된 데이터 중에서 일부를 떼어 내어 활용하는 것입니다. 일반적으로 후자의 경우가 많습니다. 이때 평가에 사용하는 데이터를 테스트 세트, 훈련에 사용되는 데이터를 훈련 세트라고 부릅니다.
이제 코딩과 함께 해보겠습니다.
먼저 도미와 빙어의 데이터를 합쳐 하나의 파이썬 리스트로 준비해줍니다. 이는 생선의 길이와 무게를 위한 리스트입니다.
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
이때 하나의 생선 데이터를 샘플이라고 부르며, 도미와 빙어는 각각 35마리, 14마리가 있으므로 전체 데이터는 49개의 샘플이 있습니다. 또한 사용하는 특성은 길이와 무게 2개입니다. 이 데이터의 처음 35개를 훈련 세트로, 나머지 14개를 테스트 세트로 사용합니다.
이후 사이킷런 의 KNeighborClassifier 클래스를 임포트하고 모델 객체를 만듭니다.
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
그리고 전체 데이터에서 처음 35개를 선택해서 훈련 세트로, 이후 14개의 샘플을 테스트 세트로 만들어줍니다. 이때 리스트의 인덱스와 슬라이싱이 사용됩니다. 인덱스는 배열의 위치를 의미하며, 슬라이싱은 클론(:)을 가운데 두고 인덱스의 범위를 지정하여 여러 개의 원소를 선택하는 것을 말합니다.
train_input = fish_data[:35]
train_target = fish_target[:35]
test_input = fish_data[35:]
test_target = fish_target[35:]
슬라이싱 연산으로 인덱스 0~34까지 처음 35개 샘플을 훈련 세트로 선택했고, 인덱스 35~28까지 나머지 14개의 샘플을 테스트 세트로 선택했습니다. 데이터를 준비했으니 훈련 세트로 fit() 메서드를 호출해 모델을 훈련하고, 테스트 세트로 score() 메서드를 호출해 평가해 보겠습니다.
근데, 정확도가 0.0입니다. 무엇이 문제인지 살펴보도록 하겠습니다.
3. 샘플링 편향
다시 확인해보니 마지막 14개를 테스트 세트로 떼어 놓고 보니 훈련 세트에는 빙어가 하나도 들어있지 않았습니다.
fish_data 에는 처음부터 순서대로 35개의 도미와 14개의 빙어 샘플이 들어가 있습니다. 따라서 마지막 14개를 테스트 세트로 만들면 빙어 데이터만 들어갑니다!
상식적으로 훈련하는 데이터와 테스트하는 데이터에는 도미와 빙어가 골고루 섞여 있어야 합니다.
일반적으로 훈련 세트와 테스트 세트에 샘플이 골고루 섞여 있지 않으면 샘플링이 한쪽으로 치우였다는 의미로 샘플링 편향이라고 부릅니다.
이 예에서 훈련 세트에 도미만 있기 때문에 테스트 세트가 무엇이든 무조건 도미라고 분류합니다. 그런데 테스트 세트는 빙어만 있기 때문에 정답을 하나도 맞히지 못합니다.
훈련 세트와 테스트 세트를 나누기 전에 데이터를 섞든지 아니면 골고루 샘플을 뽑아서 훈련 세트와 테스트 세트를 만들어야 합니다. 이때 넘파이 라이브러리가 간편하게 처리할 수 있도록 해줍니다.
4. 넘파이
넘파이는 파이썬의 대표적인 배열 라이브러리입니다. 앞서 파이썬의 리스트로 2차원 리스트를 표현할 수 있지만 고차원 리스트를 표현하려면 매우 번거롭습니다. 넘파이는 고차원의 배열을 손쉽게 만들고 조작할 수 있는 간편한 도구를 많이 제공합니다.
1차원 배열은 선이고, 2차원 배열은 면, 3차원 배열을 3차원 공간을 나타냅니다.
보통의 xy좌표계와는 달리 시작점이 왼쪽 아래가 아니고 왼쪽 위에서부터 시작하는 특징이 있습니다.
그럼 생선 데이터를 2차원 넘파이 배열로 변환해 보겠습니다.
먼저 넘파이 라이브러리를 사용하기 위해 임포트 합니다.
import numpy as np
넘파이array() 함수에 파이썬 리스트를 전달하여, 파이썬 리스트를 넘파이 배열로 바꿔줍니다.
input_arr = np.array(fish_data)
target_arr = np.array(fish_target)
위의 input_arr의 출력결과는 아래와 같습니다.
print(input_arr)
넘파이는 위에 보이는 것처럼 배열의 차원을 구분하기 쉽도록 행과 열을 가지런히 출력합니다. 출력결과에서 49개의 행과 2개의 열이 확인할 수 있습니다.
이처럼 눈으로 확인하는 것 외에도 넘파이 배열 객체는 배열의 크기를 알려주는 shape 속성을 제공합니다. 결과는 (샘플 수, 특성 수)로 나타납니다. 코드와 결과는 아래와 같으며 49개의 샘플과 2개의 특성이 나온 것을 확인할 수 있습니다.
이제 생선 데이터를 넘파이 배열로 준비했으므로 이 배열에서 랜덤하게 샘플을 선택해 훈련 세트와 테스트 세트로 만들어보겠습니다.
이때 주의할 점은 input_arr 와 target_arr에서 같은 위치는 함께 선택되어야 한다는 점입니다. 타깃이 샘플과 함께 이동하지 않으면 올바르게 훈련될 수 없습니다.
이렇게 하려면 훈련 세트와 테스트 세트로 나눌 인덱스값을 기억하는 것이 중요합니다. 하지만 항상 인덱스 값을 기억할 수는 없으니 다른 방법이 필요합니다. 이에 대해 알아보겠습니다.
넘파이 arrange()함수를 사용하여 인덱스를 만들어줍니다. 넘파이 arrange() 함수는 정수 N을 전달하면 0에서부터 N-1까지 1씩 증가하는 배열을 만드는 역할을 수행합니다. 아래는 0에서부터 48까지 1씩 증가하는 인덱스입니다.
이후, 넘파이 random 패키지 아래에 있는 shuffle() 함수를 통해 인덱스를 랜덤하게 섞습니다.
np.random.seed(42)
index = np.arange(49)
np.random.shuffle(index)
만들어진 인덱스의 결과는 아래와 같습니다.
0부터 48까지 정수가 잘 섞였습니다. 이를 사용해 전체 데이터르 훈련 세트와 테스트 세트로 나누겠습니다.
넘파이는 슬라이싱 외에 배열 인덱싱이란 기능을 제공합니다. 배열 인덱싱은 1개의 인덱스가 아닌 여러 개의 인덱스로 한 번에 여러 개의 원소를 선택할 수 있습니다. 또한 비슷한 방식으로 리스트 대신 넘파이 배열을 인덱스로 전달할 수도 있습니다.
앞서 만든 index 배열의 처음 35개를 input_arr 에 전달하면 랜덤하게 35개의 샘플이 훈련 세트로 만들어집니다.
train_input = input_arr[index[:35]]
train_target = target_arr[index[:35]]
만들어진 index의 첫 번째 값은 13입니다. 따라서 train_input의 첫 번째 원소는 input_arr의 열네 번째 원소가 들어 있을 것입니다. 확인해보면 결과는 아래와 같습니다.
나머지 14개도 동일한 방법으로 테스트 세트로 만들줍니다.
test_input = input_arr[index[35:]]
test_target = target_arr[index[35:]]
모든 데이터가 준비되었습니다. 위의 훈련 세트와 테스트 세트에 도미와 빙어가 잘 섞여 있는지 산점도로 그려서 확인하겠습니다.
파란색이 훈련 세트이고 주황색이 테스트 세트입니다. 양쪽에 도미와 빙어가 모두 섞여 있습니다. 의도한 대로 만들어졌으니, 모델을 다시 훈련시키겠습니다.
5. 두 번째 머신러닝 프로그램
앞서 만든 훈련 세트와 테스트 세트로 k-최근점 이웃 모델을 훈련시켜줍니다.
인덱스를 섞어 만든 train_input 과 train_target으로 모델을 훈련시켰습니다. 다음은 test_input과 test_target으로 이 모델을 테스트합니다.
1.0이 나온 것을 통해 100%의 정확도로 테스트 세트에 있는 모든 생선은 맞힌 것을 확인할 수 있습니다. predict() 메서드로 테스트 세트의 예측 결과와 실제 타깃을 확인하면, 역시 예측 결과가 정답과 일치합니다.
이번엔 모델을 훈련할 때 들어 있지 않은 샘플로 테스트를 했기 때문에 올바르게 평가된 것까지 확인할 수 있었습니다.
6. 훈련 모델 평가
완벽한 모델을 만들었다고 생각했지만 이상한 점이 있었습니다. 그것은 바로 알고리즘이 도미와 빙어를 모두 외우고 있어서 같은 데이터로 모델을 평가하는 것이었습니다.
모델을 훈련할 때 사용한 데이터로 모델의 성능을 평가하는 것은 정답을 미리 알려주고 시험을 보는 것과 같습니다. 공정하게 점수를 매기기 위해서는 훈련에 참여하지 않는 샘플을 사용해야 합니다.
이 때문에 훈련 데이터를 훈련 세트와 테스트 세트로 나누었습니다. 훈련 세트로는 모델을 훈련하고 테스트 세트로 모델을 평가했습니다. 하지만 테스트 세트를 그냥 무작정 나누어서는 안 됩니다. 도미와 빙어를 분류하는 것이 목적이기 때문에 훈련 세트나 테스트 세트에 어느 한 생선만 들어가 있다면 올바를 학습이 이루어지지 않게 됩니다.
그렇기에 도미와 빙어를 골고루 섞어 나누기 위해 파이썬의 다차원 배열 라이브러리인 넘파이를 사용했습니다. 넘파이는 파이썬의 리스트와 비슷하지만 큰 배열을 효과적으로 다룰 수 있고 다양한 도구를 많이 제공합니다. 이번에는 넘파이의 shuffle() 함수를 사용해 배열의 인덱스를 섞었습니다.
결과는 대성공입니다. 테스트 세트에서 100%의 정확도를 달성했습니다.
'IT > [혼공머신] 혼자 공부하는 머신러닝 + 딥러닝' 카테고리의 다른 글
[혼공머신] Ch.8 이미지를 위한 인공 신경망_1. 합성곱 신경망의 구성 요소 (0) | 2023.10.11 |
---|---|
[혼공머신] Ch.5 트리 알고리즘_3. 트리의 앙상블 (0) | 2023.09.10 |
[혼공머신] Ch.5 트리 알고리즘_2. 교차 검증과 그리드 서치 (0) | 2023.09.10 |
[혼공머신] Ch.5 트리 알고리즘_1. 결정 트리 (0) | 2023.09.09 |
[혼공머신] Ch.2 데이터 다루기_2. 데이터 전처리 (0) | 2023.08.20 |