책 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:]]
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의 값과 같은 것을 확인할 수 있다.
'인공지능 > 혼자 공부하는 머신러닝 + 딥러닝' 카테고리의 다른 글
03-2 선형회귀 (0) | 2023.02.08 |
---|---|
03-1 K-최근접 이웃 회귀 (0) | 2023.02.07 |
02-2 데이터 전처리 (0) | 2023.02.06 |
01-03 마켓과 머신러닝 확인 문제 (0) | 2023.01.31 |
01-03 마켓과 머신러닝 (0) | 2023.01.31 |