입력과 타깃을 전달하여 모델을 훈련한 다음 새로운 데이터를 예측하는 데 활용
머신러닝 알고리즘의 성능을 제대로 평가하려면 훈련 데이터와 평가에 사용할 데이터가 각각 달라져야 함.
# 2차원 리스트 및 모델 객체 생성
fish_data = [[l,w] for l, w in zip(fish_length, fish_weight)]
fish_target = [1]*35 + [0]*14
## 훈련 세트와 테스트 세트로 구분
# 훈련 세트로 입력값 중 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:]
kn = kn.fit(train_input, train_target)
kn.score(test_input, test_target)
### 정답 : 0.0
훈련 세트와 테스트 세트에 샘플이 골고루 섞여 있지 않으면 샘플링이 한쪽으로 치우치는 샘플링 편향(sampling bias)이 나타남.
# Numpy 임포트
import numpy as np
# 리스트를 넘파이 배열로 바꾸기
input_arr = np.array(fish_data)
target_arr = np.array(fish_target)
# (샘플 수, 특성 수) 출력
print(input_arr.shape)
### (49, 2)
# 일정한 결과 얻기 위해 랜덤 시드(random seed) 지정
np.random.seed(42)
index = np.arange(49)
np.random.shuffle(index)
# 훈련 세트 지정
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 = kn.fit(train_input, train_target)
kn.score(test_input, test, target)
### 정답 1.0
column_stack( ) 함수는 전달받은 리스트를 일렬로 세운 다음 차례대로 나란히 연결함. 연결할 리스트는 파이썬 튜플(tuple)로 전달함.
튜플(tuple)은 리스트처럼 원소에 순서가 있지만, 한 번 만들어진 튜플은 수정할 수 없음. 따라서 매개변수 값으로 많이 사용함.
import numpy as np
np.column_stack(([1,2,3],[4,5,6]))
fish_data = np.column_stack((fish_length, fish_weight))
# np.ones()와 np.zeros()로 각각 원하는 개수의 1과 0을 채운 배열을 만들어 줌.
# 2차원 배열인 np.column_stack()이 아닌 1차원 배열인 np.concatenate() 함수를 사용함.
fish_target = np.concatenate((np.ones(35), np.zeros(14)))
print(fish_target)
train_test_split( ) 함수는 전달되는 리스트나 배열을 비율에 맞게 훈련 세트와 테스트 세트로 나누어 주고, 알아서 섞어준다.
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)
# 입력 데이터는 2차원 배열
print(train_input.shape, test_input.shape)
# 타깃 데이터는 1차원 배열
print(train_target.shape, test_target.shape)
# 도미와 빙어의 개수가 35개와 14개이므로 두 생선의 비율은 2.5:1
# 테스트 세트의 도미와 빙어의 비율은 3.3:1 (샘플링 편향)
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)
# 테스트 세트의 비율이 2.25:1이 되었음.
print(test_target)
### 결과 : [0. 0. 1. 0. 1. 0. 1. 1. 1. 1. 1. 1. 1.]
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()
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
kn.fit(train_input, train_target)
kn.score(test_input, test_target)
print(kn.predict([[25, 150]]))
### 결과 : [0.]
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.]]
print(distances)
### 결과 : [[ 92.00086956 130.48375378 130.73859415 138.32150953 138.39320793]]
x축은 범위가 좁고 (10~40), y축은 범위가 넓음. (0~1000). 따라서 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()
두 특성(길이외 무게)의 값이 스케일(범위)이 매우 다름.
데이터 전처리(data preprocessing): 알고리즘을 제대로 사용하려면 특성값을 일정한 기준으로 맞춰 주어야 함.
표준 점수(z 점수, standard score): 각 특성값이 평균에서 표준편차의 몇 배만큼 떨어져 있는지를 나타냄.
cf. 표준 편차: 분산의 제곱근으로 데이터가 분산된 정도
# np.mean() 함수는 평균을 계산함.
mean = np.mean(train_input, axis=0)
# np.std() 함수는 표준편차를 계산함.
std = np.std(train_input, axis=0)
# 계산된 평균과 표준편차 출력
print(mean, std)
### 결과 : [ 27.29722222 454.09722222] [ 9.98244253 323.29893931]
# numpy가 train_input의 모든 행에서 mean에 있는 두 평균값을 빼줌. 그다음 std에 있는 두 표준편차를 다시 모든 행에 적용함.
train_scaled = (train_input - mean) / std
브로드캐스팅(broadcasting)은 크기가 다른 넘파이 배열에서 자동으로 사칙 연산을 모든 행이나 열로 확장하여 수행하는 기능임.
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.]
# 드디어 도미(1)로 예측함.
# 확실히 길이가 25cm이고 무게가 150cm인 생선은 도미일 것임.
kneighbors( ) 함수로 이 샘플의 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()