Chapter 2. 데이터 다루기¶
2.1 Train set과 Test set¶
# 도미
bream_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]
bream_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]
# 빙어
smelt_length = [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]
smelt_weight = [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 matplotlib.pyplot as plt
plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
length = bream_length + smelt_length
weight = bream_weight + smelt_weight
2차원 리스트 생성¶
fish_data = [[l, w] for l, w in zip(length, weight)]
fish_data
[[25.4, 242.0],
[26.3, 290.0],
[26.5, 340.0],
[29.0, 363.0],
[29.0, 430.0],
[29.7, 450.0],
[29.7, 500.0],
[30.0, 390.0],
[30.0, 450.0],
[30.7, 500.0],
[31.0, 475.0],
[31.0, 500.0],
[31.5, 500.0],
[32.0, 340.0],
[32.0, 600.0],
[32.0, 600.0],
[33.0, 700.0],
[33.0, 700.0],
[33.5, 610.0],
[33.5, 650.0],
[34.0, 575.0],
[34.0, 685.0],
[34.5, 620.0],
[35.0, 680.0],
[35.0, 700.0],
[35.0, 725.0],
[35.0, 720.0],
[36.0, 714.0],
[36.0, 850.0],
[37.0, 1000.0],
[38.5, 920.0],
[38.5, 955.0],
[39.5, 925.0],
[41.0, 975.0],
[41.0, 950.0],
[9.8, 6.7],
[10.5, 7.5],
[10.6, 7.0],
[11.0, 9.7],
[11.2, 9.8],
[11.3, 8.7],
[11.8, 10.0],
[11.8, 9.9],
[12.0, 9.8],
[12.2, 12.2],
[12.4, 13.4],
[13.0, 12.2],
[14.3, 19.7],
[15.0, 19.9]]
fish_target = [1] * 35 + [0] * 14
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]
k-Nearest Neighbors¶
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
kn.fit(fish_data, fish_target)
KNeighborsClassifier()
kn.score(fish_data, fish_target)
1.0
length = 30, weight = 600인 생선 예측
kn.predict([[30,600]])
array([1])
kn.predict([[30,60]])
array([0])
kn.predict([[3,600]])
array([1])
k-Nearest Neighbors는 가까운 데이터를 참고해 구분.
- 몇 개의 데이터를 참고할까?
- default = 5개
- 파라미터 변경 가능
kn49 = KNeighborsClassifier(n_neighbors=49)
kn49.fit(fish_data, fish_target)
kn49.score(fish_data, fish_target)
0.7142857142857143
print(35/49)
0.7142857142857143
- 어떤 데이터를 넣어도 무조건 도미로 예측
- 도미만 올바르게 맞추므로 score는 35/49=0.71..
kn = KNeighborsClassifier()
kn.fit(fish_data, fish_target)
for n in range(5, 50):
kn.n_neighbors = n
score = kn.score(fish_data, fish_target)
if score < 1:
print(f"n_neighbors: {n}\nscore: {score}")
break
n_neighbors: 18
score: 0.9795918367346939
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]
2.2 데이터 전처리¶
# 도미
bream_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]
bream_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]
# 빙어
smelt_length = [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]
smelt_weight = [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]
fl = bream_length + bream_length
fw = bream_weight + smelt_weight
fish_data = [[l, w] for l, w in zip(fl, fw)]
fish_target = [1] * 35 + [0] * 14
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]
fish_data
[[25.4, 242.0],
[26.3, 290.0],
[26.5, 340.0],
[29.0, 363.0],
[29.0, 430.0],
[29.7, 450.0],
[29.7, 500.0],
[30.0, 390.0],
[30.0, 450.0],
[30.7, 500.0],
[31.0, 475.0],
[31.0, 500.0],
[31.5, 500.0],
[32.0, 340.0],
[32.0, 600.0],
[32.0, 600.0],
[33.0, 700.0],
[33.0, 700.0],
[33.5, 610.0],
[33.5, 650.0],
[34.0, 575.0],
[34.0, 685.0],
[34.5, 620.0],
[35.0, 680.0],
[35.0, 700.0],
[35.0, 725.0],
[35.0, 720.0],
[36.0, 714.0],
[36.0, 850.0],
[37.0, 1000.0],
[38.5, 920.0],
[38.5, 955.0],
[39.5, 925.0],
[41.0, 975.0],
[41.0, 950.0],
[25.4, 6.7],
[26.3, 7.5],
[26.5, 7.0],
[29.0, 9.7],
[29.0, 9.8],
[29.7, 8.7],
[29.7, 10.0],
[30.0, 9.9],
[30.0, 9.8],
[30.7, 12.2],
[31.0, 13.4],
[31.0, 12.2],
[31.5, 19.7],
[32.0, 19.9]]
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
print(fish_data[4])
[29.0, 430.0]
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)
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)
print(target_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. ]
[ 25.4 6.7]
[ 26.3 7.5]
[ 26.5 7. ]
[ 29. 9.7]
[ 29. 9.8]
[ 29.7 8.7]
[ 29.7 10. ]
[ 30. 9.9]
[ 30. 9.8]
[ 30.7 12.2]
[ 31. 13.4]
[ 31. 12.2]
[ 31.5 19.7]
[ 32. 19.9]]
[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]
fish_data
[[25.4, 242.0],
[26.3, 290.0],
[26.5, 340.0],
[29.0, 363.0],
[29.0, 430.0],
[29.7, 450.0],
[29.7, 500.0],
[30.0, 390.0],
[30.0, 450.0],
[30.7, 500.0],
[31.0, 475.0],
[31.0, 500.0],
[31.5, 500.0],
[32.0, 340.0],
[32.0, 600.0],
[32.0, 600.0],
[33.0, 700.0],
[33.0, 700.0],
[33.5, 610.0],
[33.5, 650.0],
[34.0, 575.0],
[34.0, 685.0],
[34.5, 620.0],
[35.0, 680.0],
[35.0, 700.0],
[35.0, 725.0],
[35.0, 720.0],
[36.0, 714.0],
[36.0, 850.0],
[37.0, 1000.0],
[38.5, 920.0],
[38.5, 955.0],
[39.5, 925.0],
[41.0, 975.0],
[41.0, 950.0],
[25.4, 6.7],
[26.3, 7.5],
[26.5, 7.0],
[29.0, 9.7],
[29.0, 9.8],
[29.7, 8.7],
[29.7, 10.0],
[30.0, 9.9],
[30.0, 9.8],
[30.7, 12.2],
[31.0, 13.4],
[31.0, 12.2],
[31.5, 19.7],
[32.0, 19.9]]
input_arr
array([[ 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. ],
[ 25.4, 6.7],
[ 26.3, 7.5],
[ 26.5, 7. ],
[ 29. , 9.7],
[ 29. , 9.8],
[ 29.7, 8.7],
[ 29.7, 10. ],
[ 30. , 9.9],
[ 30. , 9.8],
[ 30.7, 12.2],
[ 31. , 13.4],
[ 31. , 12.2],
[ 31.5, 19.7],
[ 32. , 19.9]])
input_arr.shape
(49, 2)
np.random.seed(42)
index = np.arange(49)
np.random.shuffle(index)
index
array([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])
input_arr[[1,3]]
array([[ 26.3, 290. ],
[ 29. , 363. ]])
train_input = input_arr[index[:35]]
train_target = target_arr[index[:35]]
train_input
array([[ 32. , 340. ],
[ 31. , 13.4],
[ 31.5, 19.7],
[ 30.7, 12.2],
[ 33. , 700. ],
[ 36. , 714. ],
[ 35. , 720. ],
[ 35. , 725. ],
[ 38.5, 955. ],
[ 33.5, 650. ],
[ 31.5, 500. ],
[ 29. , 430. ],
[ 41. , 950. ],
[ 30. , 450. ],
[ 29. , 363. ],
[ 29.7, 500. ],
[ 29.7, 8.7],
[ 29.7, 10. ],
[ 31. , 12.2],
[ 32. , 600. ],
[ 30.7, 500. ],
[ 33. , 700. ],
[ 35. , 700. ],
[ 41. , 975. ],
[ 38.5, 920. ],
[ 25.4, 242. ],
[ 30. , 9.8],
[ 39.5, 925. ],
[ 29.7, 450. ],
[ 37. , 1000. ],
[ 31. , 500. ],
[ 26.3, 7.5],
[ 26.3, 290. ],
[ 34. , 685. ],
[ 26.5, 340. ]])
test_input = input_arr[index[35:]]
test_target = target_arr[index[35:]]
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
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])
np.column_stack(([1,2,3], [4,5,6]))
array([[1, 4],
[2, 5],
[3, 6]])
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 = np.column_stack((fish_length, fish_weight))
fish_data[:5]
array([[ 25.4, 242. ],
[ 26.3, 290. ],
[ 26.5, 340. ],
[ 29. , 363. ],
[ 29. , 430. ]])
fish_target = np.concatenate((np.ones(35), np.zeros(14)))
fish_target
array([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.])
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(fish_data, fish_target, stratify=fish_target, random_state=42)
train_input.shape
(36, 2)
train_target.shape
(36,)
test_target
array([0., 0., 1., 0., 1., 0., 1., 1., 1., 1., 1., 1., 1.])
kn = KNeighborsClassifier()
kn.fit(train_input, train_target)
kn.score(test_input, test_target)
1.0
kn.predict([[25,150]])
array([0.])
import matplotlib.pyplot as plt
plt.figure(figsize=(20,8))
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(25, 150, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.legend(('train_input', 'test_fish'))
plt.show()
distances, indexes = kn.kneighbors([[25, 150]])
distances
array([[ 92.00086956, 130.48375378, 130.73859415, 138.32150953,
138.39320793]])
indexes
array([[21, 33, 19, 30, 1]])
train_input
array([[ 29.7, 500. ],
[ 12.2, 12.2],
[ 33. , 700. ],
[ 11.3, 8.7],
[ 39.5, 925. ],
[ 29. , 430. ],
[ 36. , 714. ],
[ 36. , 850. ],
[ 31. , 475. ],
[ 35. , 720. ],
[ 37. , 1000. ],
[ 11.2, 9.8],
[ 34.5, 620. ],
[ 12. , 9.8],
[ 29. , 363. ],
[ 33. , 700. ],
[ 30.7, 500. ],
[ 38.5, 955. ],
[ 33.5, 650. ],
[ 14.3, 19.7],
[ 31.5, 500. ],
[ 25.4, 242. ],
[ 9.8, 6.7],
[ 32. , 600. ],
[ 10.5, 7.5],
[ 33.5, 610. ],
[ 10.6, 7. ],
[ 35. , 700. ],
[ 32. , 600. ],
[ 35. , 725. ],
[ 13. , 12.2],
[ 30. , 450. ],
[ 32. , 340. ],
[ 15. , 19.9],
[ 30. , 390. ],
[ 41. , 975. ]])
plt.figure(figsize=(20,8))
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.legend(('train_input', 'test_fish', 'nearest_neighbors'))
plt.show()
train_input[indexes,0]
array([[25.4, 15. , 14.3, 13. , 12.2]])
train_input[indexes,]
array([[[ 25.4, 242. ],
[ 15. , 19.9],
[ 14.3, 19.7],
[ 13. , 12.2],
[ 12.2, 12.2]]])
train_input[indexes]
array([[[ 25.4, 242. ],
[ 15. , 19.9],
[ 14.3, 19.7],
[ 13. , 12.2],
[ 12.2, 12.2]]])
indexes
array([[21, 33, 19, 30, 1]])
train_target[indexes]
array([[1., 0., 0., 0., 0.]])
distances
array([[ 92.00086956, 130.48375378, 130.73859415, 138.32150953,
138.39320793]])
도미까지의 거리 92만 가깝고, 나머지(빙어)까지는 다 130 넘음.
근데 위 그래프에선 92까지의 거리인 도미가 더 가까워보이지 않나?
-> x축과 y축의 범위가 다르기 때문!
다른 말로 하면 두 특성 간 스케일(scale)이 다른 것.
해결법: 기준(범위)을 맞추자
0 ~ 1,000
plt.figure(figsize=(20,8))
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.legend(('train_input', 'test_fish', 'nearest_neighbors'))
plt.show()
데이터 표현 기준이 다르면 알고리즘이 올바르게 예측할 수 없음. 특히 거리 기반일 때 더더욱(k-nearest neighbor).
따라서 특성값을 일정한 기준으로 맞춰 주어야 함. 이 작업을 데이터 전처리(data preprocessing)라고 부름.
가장 널리 사용하는 전처리 방법 중 하나는 표준점수(standard score)(혹은 z score)이다.
- 표준점수: 각 특성값이 평균에서 표준편차의 몇 배만큼 떨어져있는지를 나타냄(몇 표준편차만큼 떨어져 있는가)
# train_input은 (36, 2) 크기의 배열. 특성마다 값의 scale이 다르므로 각 특성별로 계산해야 함.
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]
# standard score(z score)
train_scaled = (train_input - mean) / std
train_scaled
array([[ 0.24070039, 0.14198246],
[-1.51237757, -1.36683783],
[ 0.5712808 , 0.76060496],
[-1.60253587, -1.37766373],
[ 1.22242404, 1.45655528],
[ 0.17057727, -0.07453542],
[ 0.87180845, 0.80390854],
[ 0.87180845, 1.22457184],
[ 0.37092904, 0.06465464],
[ 0.77163257, 0.82246721],
[ 0.97198434, 1.68853872],
[-1.61255346, -1.3742613 ],
[ 0.72154463, 0.51315596],
[-1.53241275, -1.3742613 ],
[ 0.17057727, -0.28177396],
[ 0.5712808 , 0.76060496],
[ 0.34087627, 0.14198246],
[ 1.12224816, 1.54934866],
[ 0.62136874, 0.60594934],
[-1.30200822, -1.34363949],
[ 0.42101698, 0.14198246],
[-0.19005591, -0.65604058],
[-1.75279969, -1.38384995],
[ 0.47110492, 0.45129371],
[-1.68267658, -1.38137546],
[ 0.62136874, 0.48222484],
[-1.67265899, -1.38292202],
[ 0.77163257, 0.76060496],
[ 0.47110492, 0.45129371],
[ 0.77163257, 0.83793278],
[-1.43223687, -1.36683783],
[ 0.27075315, -0.01267317],
[ 0.47110492, -0.35291555],
[-1.2318851 , -1.34302087],
[ 0.27075315, -0.19825992],
[ 1.37268787, 1.61121091]])
Broadcasting¶
넘파이 배열 사이에서 일어남.
train_input의 모든 행에서 mean에 있는 두 평균값을 빼준 뒤, std에 있는 두 표준편차를 다시 모든 행에 적용.
전처리 데이터로 모델 훈련¶
표준점수로 변환한 train_scaled로 산점도 그려보자
plt.figure(figsize=(20,8))
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(25, 150, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.legend(('train set', 'sample'))
plt.show()
이상한 이유: train_input을 표준점수로 변환했는데, 저 [25, 150]은 안 해줬으므로.
아주 중요한 것: train set의 mean, std를 이용해서 sample도 변환해야 한다.¶
new = ([25, 150] - mean) / std
plt.figure(figsize=(20,8))
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(new[0], new[1], marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.legend(('train set', 'standardized sample'))
plt.show()
new = ([25, 150] - mean) / std
new
array([-0.23012627, -0.94060693])
이제 훈련 데이터의 두 특성이 비슷한 범위를 차지하고 있으므로, 이 데이터셋으로 다시 k-nearest neighbor 훈련해보자.
# 모델 훈련(fit)
kn.fit(train_scaled, train_target)
KNeighborsClassifier()
# test set(test_input)도 마찬가지로 mean과 std로 변환해야 함
test_scaled = (test_input - mean) / std
# 모델 평가
kn.score(test_scaled, test_target)
1.0
kn.predict([new])
array([1.])
이 sample의 k-nearest neighbor을 구한 다음 산점도로 나타내자.
(특성을 표준점수로 바꾸었기 때문에 k-nearest neighbor algorithm이 올바르게 거리를 측정했을 것)
distances, indexes = kn.kneighbors([new])
plt.figure(figsize=(20,8))
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.legend(('standardized train set', 'standardized sample', 'nearnes samples'))
plt.show()
이제 표준화된 sample([25, 150])에서 가장 가까운 samples는 모두 도미!
따라서 이 sample([25, 150])을 도미로 예측하는 것이 당연.
성공!
-> 특성값의 scale에 민감하지 않고 안정적인 예측을 할 수 있는 모델을 만들었다. 특성의 scale이 다르면 대부분의 ML algo가 잘 작동하지 않음. 이를 위해 특성을 표준점수로 변환함(표준점수 말고도 scale 조정할 수 있는 방법들이 있긴 한데 대부분 표준점수면 충분하고, 또 가장 널리 사용함).
- 주의할 점: train set 변환한 방식 그대로 test set 변환해야 함.
Chapter 3¶
3-1. k-최근접 이웃 회귀¶
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
perch_length = np.array([8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0, 21.0,
21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5, 22.5, 22.7,
23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5, 27.3, 27.5, 27.5,
27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0, 36.5, 36.0, 37.0, 37.0,
39.0, 39.0, 39.0, 40.0, 40.0, 40.0, 40.0, 42.0, 43.0, 43.0, 43.5,
44.0])
perch_weight = np.array([5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0, 110.0,
115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0, 130.0,
150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0, 197.0,
218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0, 514.0,
556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0, 820.0,
850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0, 1000.0,
1000.0])
plt.scatter(perch_length, perch_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
train_input, test_input, train_target, test_target = train_test_split(perch_length, perch_weight, random_state=42)
# 2차원 배열로 shape 바꾸기
ta = np.array([1,2,3,4])
ta.shape
(4,)
ta = ta.reshape(2, 2)
ta.shape
(2, 2)
ta
array([[1, 2],
[3, 4]])
train_input = train_input.reshape(-1, 1) # = (42, 1)
test_input = test_input.reshape(-1, 1)
print(train_input.shape, test_input.shape)
(42, 1) (14, 1)
결정계수(R2)¶
Classification의 경우는 score가 '샘플을 정확하게 분류한 개수의 비율', 즉 정확도.
회귀에서는 결정계수(R2).
R2=1−(타깃−예측)2의합(타깃−평균)2의합
from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor()
knr.fit(train_input, train_target)
knr.score(test_input, test_target)
0.992809406101064
0.99가 얼마나 좋은 건가?
target과 predict한 값의 차이를 구해보자.
from sklearn.metrics import mean_absolute_error
# test set에 대한 prediction 생성
test_prediction = knr.predict(test_input)
# test set에 대한 평균 절댓값 오차를 계산
mae = mean_absolute_error(test_target, test_prediction)
mae
19.157142857142862
약 19g 정도 target value와 다름.
과대적합 vs 과소적합¶
train set으로 훈련한 모델을 사용해 train set의 R2 점수 확인해보자.
knr.score(train_input, train_target)
0.9698823289099254
왜 train으로 훈련시키고 train으로 score 뽑았는데 점수가 test set score보다 낮을까?
- 일반적으로 train set score가 조금 더 높게 나옴
- 만약 train set에서 점수가 좋았는데, test set에서 나쁘다면 모델이 train set에 과대적합(overfitting)되었다고 함
- 반대로 train set보다 test set의 score가 더 높거나, 두 score가 모두 너무 낮은 경우에는 과소적합(underfitting)되었다고 말함
- 즉 모델이 너무 단순하여 train set에 적절히 훈련되지 않은 경우임
- train set이 전체 data르 대표한다고 가정하기 때문에 train set을 잘 학습하는 것이 중요
선형회귀와 다항회귀는 저자 분의 gitHub repo를 참고하자
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
# 선형 회귀 모델 훈련
lr.fit(train_input, train_target)
LinearRegression()
# 50cm 농어에 대한 예측
print(lr.predict([[50]]))
[1241.83860323]
print(lr.coef_, lr.intercept_)
[39.01714496] -709.0186449535477
# 훈련 세트의 산점도를 그립니다
plt.scatter(train_input, train_target)
# 15에서 50까지 1차 방정식 그래프를 그립니다
plt.plot([15, 50], [15*lr.coef_+lr.intercept_, 50*lr.coef_+lr.intercept_])
# 50cm 농어 데이터
plt.scatter(50, 1241.8, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
print(lr.score(train_input, train_target))
print(lr.score(test_input, test_target))
0.939846333997604
0.8247503123313558
다항회귀¶
train_poly = np.column_stack((train_input ** 2, train_input))
test_poly = np.column_stack((test_input ** 2, test_input))
train_input
array([[19.6],
[22. ],
[18.7],
[17.4],
[36. ],
[25. ],
[40. ],
[39. ],
[43. ],
[22. ],
[20. ],
[22. ],
[24. ],
[27.5],
[43. ],
[40. ],
[24. ],
[21. ],
[27.5],
[40. ],
[32.8],
[26.5],
[36.5],
[13.7],
[22.7],
[15. ],
[37. ],
[35. ],
[28.7],
[23.5],
[39. ],
[21. ],
[23. ],
[22. ],
[44. ],
[22.5],
[19. ],
[37. ],
[22. ],
[25.6],
[42. ],
[34.5]])
train_input.shape
(42, 1)
train_input ** 2
array([[ 384.16],
[ 484. ],
[ 349.69],
[ 302.76],
[1296. ],
[ 625. ],
[1600. ],
[1521. ],
[1849. ],
[ 484. ],
[ 400. ],
[ 484. ],
[ 576. ],
[ 756.25],
[1849. ],
[1600. ],
[ 576. ],
[ 441. ],
[ 756.25],
[1600. ],
[1075.84],
[ 702.25],
[1332.25],
[ 187.69],
[ 515.29],
[ 225. ],
[1369. ],
[1225. ],
[ 823.69],
[ 552.25],
[1521. ],
[ 441. ],
[ 529. ],
[ 484. ],
[1936. ],
[ 506.25],
[ 361. ],
[1369. ],
[ 484. ],
[ 655.36],
[1764. ],
[1190.25]])
(train_input ** 2).shape
(42, 1)
print(train_poly.shape, test_poly.shape)
(42, 2) (14, 2)
lr = LinearRegression()
lr.fit(train_poly, train_target)
print(lr.predict([[50**2, 50]]))
[1573.98423528]
print(lr.coef_, lr.intercept_)
[ 1.01433211 -21.55792498] 116.0502107827827
# 구간별 직선을 그리기 위해 15에서 49까지 정수 배열을 만듭니다
point = np.arange(15, 50)
# 훈련 세트의 산점도를 그립니다
plt.scatter(train_input, train_target)
# 15에서 49까지 2차 방정식 그래프를 그립니다
plt.plot(point, 1.01*point**2 - 21.6*point + 116.05)
# 50cm 농어 데이터
plt.scatter([50], [1574], marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
print(lr.score(train_poly, train_target))
print(lr.score(test_poly, test_target))
0.9706807451768623
0.9775935108325122
'Machine Learning & Deep Learning' 카테고리의 다른 글
[머신러닝] 특성공학과 규제 (0) | 2022.02.24 |
---|
댓글