챕터 1에서는 입력과 타깃이 있었음으로 지도 학습이였음
머신 러닝의 정확한 평가 위해 테스트 세트와 훈련 세트는 따로 준비되어야 함
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
여기서 하나의 생선 데이터를 샘플 이라고 함!
사이킷런 의 K ~~클래스 임포트 후 모델 객체 생성
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
전체 데이터에서 처음 35개 선택해야 함
리스트 같이 배열 요소 선택할 떄는 인덱스(배열의 위치) 지정함
아래는 다섯번째 샘플을 출력하는 예제
print(fish_data[4])
! 슬라이싱에서 마지막 인덱스 원소는 포함X
주의하삼
print(fish_data[0:5])
print(fish_data[:5])
print(fish_data[44:])
train_input = fish_data[:35]
train_target = fish_target[:35]
test_input = fish_data[35:]
test_target = fish_target[35:]
kn.fit(train_input, train_target)
kn.score(test_input, test_target)
결과는 0.0 ……
💡왜 이런 결과가 나오지?
그럼 어떻게 해?
훈련 데이터와 테스트 데이터에 도미랑 방어가 골고루 섞여야함
이러한 데이터 비빔밥 맛집이 있다고 한다.

import numpy as np
input_arr = np.array(fish_data)
target_arr = np.array(fish_target)
print(input_arr)
[[ 25.4 242. ]
[ 26.3 290. ]
[ 26.5 340. ]
[ 29. 363. ]
[ 29. 430. ]
[ 29.7 450. ]
[ 29.7 500. ]
[ 30. 390. ]
[ 30. 450. ]
[ 30.7 500. ]
[ 31. 475. ]
[ 31. 500. ]
[ 31.5 500. ]
[ 32. 340. ]
[ 32. 600. ]
[ 32. 600. ]
[ 33. 700. ]
[ 33. 700. ]
[ 33.5 610. ]
[ 33.5 650. ]
[ 34. 575. ]
[ 34. 685. ]
[ 34.5 620. ]
[ 35. 680. ]
[ 35. 700. ]
[ 35. 725. ]
[ 35. 720. ]
[ 36. 714. ]
[ 36. 850. ]
[ 37. 1000. ]
[ 38.5 920. ]
[ 38.5 955. ]
[ 39.5 925. ]
[ 41. 975. ]
[ 41. 950. ]
[ 9.8 6.7]
[ 10.5 7.5]
[ 10.6 7. ]
[ 11. 9.7]
[ 11.2 9.8]
[ 11.3 8.7]
[ 11.8 10. ]
[ 11.8 9.9]
[ 12. 9.8]
[ 12.2 12.2]
[ 12.4 13.4]
[ 13. 12.2]
[ 14.3 19.7]
[ 15. 19.9]]

어때요, 참 쉽죠?
print(input_arr.shape)
(49, 2)
(샘플 수, 특성 수)
의 형태이다.
주의 사항
np.random.seed(42)
index = np.arange(49)
np.random.shuffle(index)
print(index)
# 곃과
[13 45 47 44 17 27 26 25 31 19 12 4 34 8 3 6 40 41 46 15 9 16 24 33
30 0 43 32 5 29 11 36 1 21 2 37 35 23 39 10 22 18 48 20 7 42 14 28
38]
이븐하게 잘 비벼졌습니다.
ex. 두번째와 네번째 샘플 선택
print(input_arr[[1, 3]])
# 결과
[[ 26.3 290. ]
[ 29. 363. ]]
train_input = input_arr[index[:35]]
train_target = target_arr[index[:35]]
test_input = input_arr[index[35:]]
test_target = target_arr[index[35:]]
import matplotlib.pyplot as plt
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)
1.0
100% 다!
근데 수업에서 100%여도 마냥 좋은건 아니라 하신것 같은데
나중에 나오겠죠 뭐
kn.predict(test_input)
#결과
array([0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0])
test_target
#결과
array([0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0])
오늘의 작은 성공!
하지만 이렇게 만든 모델도 나사가 조금 많이 빠진 녀석이다…
다시 데이터 준비
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]
import numpy as np
fish_data = np.column_stack((fish_length, fish_weight))
print(fish_data[:5])
# 결과 무계와 길이가 순서대로 짝지어짐
[[ 25.4 242. ]
[ 26.3 290. ]
[ 26.5 340. ]
[ 29. 363. ]
[ 29. 430. ]]
함수 내부 구조는 안 뜯어봐서 효율이나 작동 방식은 안 찾아봤는데
시간이 너무 없으니 다음으로 기약 후 넘어가자…
이제 타겟 데이터를 만들어야 한다.
전에는 [1], [0]을 여러번 곱해 만들었는데 이제 함수사용해 날로먹자
ex)숫자 1로만 이루어진 길이가 5인 배열
print(np.ones(5))
[1. 1. 1. 1. 1.]
fish_target = np.concatenate((np.ones(35), np.zeros(14)))
print(fish_target)
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0.]
근데 결과가 이진인데 float으로 할 필요가 있나? 메모리 낭비 같은데…
무튼 다음 단계로
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(fish_data, fish_target, random_state=42)
random_state 는 랜덤시드 지정 매개변수
print(train_input.shape, test_input.shape)
(36, 2) (13, 2)
print(train_target.shape, test_target.shape)
(36,) (13,)
print(test_target)
[1. 0. 0. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
stratify 매개변수에 타깃 게이터를 전달하면 클래스 비율에 맞게 데이터를 나눠줌
train_input, test_input, train_target, test_target = train_test_split(fish_data, fish_target, stratify=fish_target, random_state=42)
print(test_target)
[0. 0. 1. 0. 1. 0. 1. 1. 1. 1. 1. 1. 1.]

이븐하게 비벼진 모습
이제 다시 K-어쩌구 이웃 훈련을 하자
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
kn.fit(train_input, train_target)
kn.score(test_input, test_target)
1.0
모든 생선들을 바르게 분류했다 이제 전에 문제가 발생한 도미 데이터를 넣어보자
print(kn.predict([[25, 150]]))
[0.]

왜 빙어라고 하는거야…
이 샘플을 다른 데이터와 함께 산점도로 확인해 보자
import matplotlib.pyplot as plt
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(25, 150, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

ㅏ….
distances, indexes = kn.kneighbors([[25, 150]])
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(25, 150, marker='^')
plt.scatter(train_input[indexes,0], train_input[indexes,1], marker='D')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

print(train_target[indexes])
[[1. 0. 0. 0. 0.]]
가까운 생선 중 4개가 빙어다.
거리 값도 확인하wk
print(distances)
[[ 92.00086956 130.48375378 130.73859415 138.32150953 138.39320793]]


이렇게 떨어져 있는데 40정도밖에 차이가 안 난다고?
x축과 y축의 범위가 다르다.
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(25, 150, marker='^')
plt.scatter(train_input[indexes,0], train_input[indexes,1], marker='D')
plt.xlim((0, 1000))
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

이렇게 보니 생선의 키는 고만고만이라 별 영향력이 없어보인다.
특히 알고리즘이 거리 기반이면 데이터 전처리를 꼭 해주어야 올바른 예측이 가능하다.
방법은 간단함
표준편차 계산 함수
mean = np.mean(train_input, axis=0)
std = np.std(train_input, axis=0)
print(mean, std)
[ 27.29722222 454.09722222] [ 9.98244253 323.29893931]
axis의 의미axis=0: 열(column) 단위 연산 → 각 특성(feature)별 평균, 표준편차 계산axis=1: 행(row) 단위 연산 → 각 샘플(sample)별 평균, 표준편차 계산axis를 지정하지 않으면 전체 배열을 기준으로 연산 수행특성마다 평균, 표준편차를 구했으니 원본 데이터에서 평균을 빼고 표준 편차로 나누어 표준 점수로 변환하자
train_scaled = (train_input - mean) / std
이 식에서
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(25, 150, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()


new = ([25, 150] - mean) / std
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(new[0], new[1], marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

이제 다시 K-최근점 이웃 모델을 훈련하자!
kn.fit(train_scaled, train_target)
test_scaled = (test_input - mean) / std
kn.score(test_scaled, test_target)
1.0
이제 문제의 케이스를 예측해 보자
print(kn.predict([new]))
[1.]
성공이다
마지막으로 다시 k-최근점 이웃을 구하고 산점도로 그려보자
distances, indexes = kn.kneighbors([new])
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(new[0], new[1], marker='^')
plt.scatter(train_scaled[indexes,0], train_scaled[indexes,1], marker='D')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

가까운 샘플은 모두 도미이다.