Hi-λžŒπŸ‘‹ High-λžŒβ˜€οΈ

02-1 ν›ˆλ ¨ μ„ΈνŠΈμ™€ ν…ŒμŠ€νŠΈ μ„ΈνŠΈ λ³Έλ¬Έ

λ¨Έμ‹ λŸ¬λ‹/혼자 κ³΅λΆ€ν•˜λŠ” λ¨Έμ‹ λŸ¬λ‹ + λ”₯λŸ¬λ‹

02-1 ν›ˆλ ¨ μ„ΈνŠΈμ™€ ν…ŒμŠ€νŠΈ μ„ΈνŠΈ

ν•˜μ΄λžŒ 2021. 8. 26. 01:21

μ§€λ‚œ μ±•ν„°μ—μ„œλŠ” 정확도 100%인 도미와 λΉ™μ–΄λ₯Ό λΆ„λ₯˜ν•˜λŠ” λ¨Έμ‹ λŸ¬λ‹ λͺ¨λΈμ„ λ§Œλ“€μ—ˆλ‹€. 그런데 사싀 λͺ¨λ“  생선에 λŒ€ν•œ 닡을 μ•Œκ³  μžˆλŠ”λ° λ§žμΆ”μ§€ λͺ»ν•˜λŠ” 것이 μ΄μƒν•˜λ‹€. 이 λ¬Έμ œλŠ” μ–΄λ–»κ²Œ ν•΄κ²°ν•˜λ©΄ μ’‹μ„κΉŒ?

 

지도 ν•™μŠ΅κ³Ό 비지도 ν•™μŠ΅ 

 

λ¨Έμ‹ λŸ¬λ‹ μ•Œκ³ λ¦¬μ¦˜μ€ 크게 지도 ν•™μŠ΅κ³Ό 비지도 ν•™μŠ΅μœΌλ‘œ λ‚˜λˆŒ 수 μžˆλ‹€. 지도 ν•™μŠ΅ μ•Œκ³ λ¦¬μ¦˜μ€ ν›ˆλ ¨ν•˜κΈ° μœ„ν•œ 데이터와 정닡이 ν•„μš”ν•˜λ‹€. 1μž₯μ—μ„œλŠ” 도미인지 μ•„λ‹Œμ§€ μ—¬λΆ€κ°€ 정닡에 ν•΄λ‹Ήν–ˆλ‹€. 지도 ν•™μŠ΅μ—μ„œλŠ” 데이터와 정닡을 각각 μž…λ ₯κ³Ό 타깃이라고 ν•˜κ³ , 이 λ‘˜μ„ ν•©μ³μ„œ ν›ˆλ ¨ 데이터라고 λΆ€λ₯Έλ‹€. 지도 ν•™μŠ΅μ€ 정닡을 λ§žνžˆλŠ” 것을 ν•™μŠ΅ν•œλ‹€. 반면 비지도 ν•™μŠ΅ μ•Œκ³ λ¦¬μ¦˜μ€ 정닡을 μ‚¬μš©ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— 무언가λ₯Ό 맞힐 μˆ˜λŠ” μ—†μœΌλ©°, λ‹€λ§Œ 데이터λ₯Ό 잘 νŒŒμ•…ν•˜κ±°λ‚˜ λ³€ν˜•ν•˜λŠ” 데 도움을 μ€€λ‹€. 

 

 

ν›ˆλ ¨ μ„ΈνŠΈμ™€ ν…ŒμŠ€νŠΈ μ„ΈνŠΈ

 

μ‹œν—˜μ„ 보기 전에 좜제될 μ‹œν—˜ λ¬Έμ œμ™€ 정닡을 미리 μ•Œλ €μ£Όκ³  μ‹œν—˜μ„ 보면 λ‹Ήμ—°νžˆ 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]

fish_data = [[l,w] for l,w in zip(fish_length, fish_weight)]
fish_target=[1]*35 + [0]*14

 

그리고 μ‚¬μ΄ν‚·λŸ°μ˜ KNeighborsClassifier 클래슀λ₯Ό μž„ν¬νŠΈν•˜κ³  λͺ¨λΈ 객체λ₯Ό λ§Œλ“ λ‹€.

 

from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()

 

이제 전체 λ°μ΄ν„°μ—μ„œ 처음 35개λ₯Ό 선택해야 ν•œλ‹€. 파이썬 λ¦¬μŠ€νŠΈλŠ” μŠ¬λΌμ΄μ‹±μ΄λΌλŠ” νŠΉλ³„ν•œ μ—°μ‚°μžλ₯Ό μ œκ³΅ν•˜λŠ”λ°, 이 연산을 μ‚¬μš©ν•˜λ©΄ 인덱슀의 λ²”μœ„λ₯Ό μ§€μ •ν•˜μ—¬ μ›μ†Œλ₯Ό μ—¬λŸ¬ 개 선택할 수 μžˆλ‹€. μ—¬κΈ°μ„œ μ£Όμ˜ν•  점은 λ§ˆμ§€λ§‰ 인덱슀의 μ›μ†ŒλŠ” ν¬ν•¨λ˜μ§€ μ•ŠλŠ”λ‹€λŠ” 점이닀. 이λ₯Ό μ‘μš©ν•˜μ—¬ 생선 λ°μ΄ν„°μ—μ„œ 처음 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~48κΉŒμ§€ λ‚˜λ¨Έμ§€ 14개의 μƒ˜ν”Œμ„ ν…ŒμŠ€νŠΈ μ„ΈνŠΈλ‘œ μ„ νƒν–ˆλ‹€. 데이터λ₯Ό μ€€λΉ„ν–ˆμœΌλ‹ˆ ν›ˆλ ¨ μ„ΈνŠΈλ‘œ fit() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•΄ λͺ¨λΈμ„ ν›ˆλ ¨ν•˜κ³ , ν…ŒμŠ€νŠΈ μ„ΈνŠΈλ‘œ score() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•΄ ν‰κ°€ν•΄λ³΄μž.

 

kn=kn.fit(train_input, train_target)
kn.score(test_input, test_target)

0.0

 

정확도λ₯Ό ν™•μΈν•΄λ³΄λ‹ˆ 0.0이닀. μ™œ 이런 λ¬Έμ œκ°€ 생긴 κ²ƒμΌκΉŒ?

 

μ΄λŠ” 잘λͺ»λœ ν›ˆλ ¨ λ°μ΄ν„°λ‘œλΆ€ν„° 생긴 λ¬Έμ œμ΄λ‹€. μ˜¬λ°”λ₯Έ ν›ˆλ ¨ λ°μ΄ν„°λŠ” 도미와 λΉ™μ–΄κ°€ 골고루 μ„žμ—¬μžˆμ–΄μ•Ό ν•œλ‹€. 이처럼 ν›ˆλ ¨ μ„ΈνŠΈμ™€ ν…ŒμŠ€νŠΈ μ„ΈνŠΈμ— μƒ˜ν”Œμ΄ 골고루 μ„žμ—¬ μžˆμ§€ μ•Šμ€ 상황을 μƒ˜ν”Œλ§ 편ν–₯이라고 λΆ€λ₯Έλ‹€. μƒ˜ν”Œλ§ 편ν–₯ 문제λ₯Ό ν•΄κ²°ν•˜λ €λ©΄, ν›ˆλ ¨ μ„ΈνŠΈμ™€ ν…ŒμŠ€νŠΈ μ„ΈνŠΈλ₯Ό λ‚˜λˆ„κΈ° 전에 데이터λ₯Ό μ„žλ“ μ§€ μ•„λ‹ˆλ©΄ 골고루 μƒ˜ν”Œμ„ λ½‘μ•„μ„œ ν›ˆλ ¨ μ„ΈνŠΈμ™€ ν…ŒμŠ€νŠΈ μ„ΈνŠΈλ₯Ό λ§Œλ“€μ–΄μ•Ό ν•œλ‹€. 이 μž‘μ—…μ„ μœ„ν•΄ λ„˜νŒŒμ΄μ— λŒ€ν•΄ μ•Œμ•„λ³΄μž.

 

 

λ„˜νŒŒμ΄

 

λ„˜νŒŒμ΄(numpy)λŠ” 파이썬의 λŒ€ν‘œμ μΈ λ°°μ—΄ λΌμ΄λΈŒλŸ¬λ¦¬μ΄λ‹€. λ„˜νŒŒμ΄λŠ” κ³ μ°¨μ›μ˜ 배열을 μ†μ‰½κ²Œ λ§Œλ“€κ³  μ‘°μž‘ν•  수 μžˆλŠ” κ°„νŽΈν•œ 도ꡬλ₯Ό 많이 μ œκ³΅ν•œλ‹€. 

 

그럼 생선 데이터λ₯Ό 2차원 λ„˜νŒŒμ΄ λ°°μ—΄λ‘œ λ³€ν™˜ν•΄λ³΄μž. λ¨Όμ € λ„˜νŒŒμ΄ 라이브러리λ₯Ό μž„ν¬νŠΈν•˜κ³ , λ„˜νŒŒμ΄ array() ν•¨μˆ˜μ— 파이썬 리슀트λ₯Ό μ „λ‹¬ν•˜λ©΄ λœλ‹€.

 

import numpy as np

input_arr = np.array(fish_data)
target_arr = np.array(fish_target)

 

μ΄λ ‡κ²Œ λ³€ν™˜ν•œ input_arr 배열을 좜λ ₯해보면 λ‹€μŒκ³Ό 같이 2개의 μ—΄(νŠΉμ„±)κ³Ό 49개의 ν–‰(μƒ˜ν”Œ)을 κ°€μ§„ λ°°μ—΄μž„μ„ μ•Œ 수 μžˆλ‹€.

[[ 25.4 242. ],

 [ 26.3 290. ],

     .      .    

     .      .    

  [ 15. 19.9 ]]

 

μ΄λ ‡κ²Œ 좜λ ₯해보지 μ•Šμ•„λ„ λ„˜νŒŒμ΄ λ°°μ—΄ κ°μ²΄λŠ” λ°°μ—΄μ˜ 크기λ₯Ό μ•Œλ €μ£ΌλŠ” shape 속성을 μ œκ³΅ν•œλ‹€. 이 λͺ…령을 μ‚¬μš©ν•˜λ©΄ (μƒ˜ν”Œ 수, νŠΉμ„± 수)λ₯Ό 좜λ ₯ν•œλ‹€.

print(input_arr.shape)

(49,2)

 

이제 생선 데이터λ₯Ό λ„˜νŒŒμ΄ λ°°μ—΄λ‘œ μ€€λΉ„ν–ˆμœΌλ―€λ‘œ λ¬΄μž‘μœ„ν•˜κ²Œ μƒ˜ν”Œμ„ 골라보자. μ—¬κΈ°μ„œ μ£Όμ˜ν•  점은 input_arrκ³Ό target_arrμ—μ„œ 같은 μœ„μΉ˜λŠ” ν•¨κ»˜ μ„ νƒλ˜μ–΄μ•Ό ν•œλ‹€. λ‹€μ‹œ λ§ν•΄μ„œ 타깃이 μƒ˜ν”Œκ³Ό ν•¨κ»˜ 이동해야 ν•œλ‹€λŠ” 뜻이고, 이λ₯Ό μœ„ν•΄μ„œ μ•„μ˜ˆ 인덱슀λ₯Ό μ„žκ³  그에 ν•΄λ‹Ήν•˜λŠ” input_arr 와 target_arr을 μ„ νƒν•˜λŠ” 방식을 νƒν•œλ‹€.

 

λ„˜νŒŒμ΄ arange() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•΄μ„œ 0μ—μ„œλΆ€ν„° 48κΉŒμ§€μ˜ 인덱슀λ₯Ό λ§Œλ“€κ³  이 인덱슀λ₯Ό λžœλ€ν•˜κ²Œ μ„žλŠ”λ‹€. μ›λž˜ λ„˜νŒŒμ΄μ—μ„œλŠ” μ‹€ν–‰ν•  λ•Œλ§ˆλ‹€ λ‹€λ₯Έ κ²°κ³Όλ₯Ό λ§Œλ“€μ§€λ§Œ, μ±…κ³Ό λ™μΌν•œ κ²°κ³Όλ₯Ό μ–»κΈ° μœ„ν•΄μ„œ μ—¬κΈ°μ„œλŠ” 랜덀 μ‹œλ“œλ₯Ό μ§€μ •ν•΄μ£Όμ—ˆλ‹€.

np.random.seed(42)
index = np.arange(49)
np.random.shuffle(index)

 

μ΄λ ‡κ²Œ λ§Œλ“  ν›„ λ°°μ—΄ 인덱싱 κΈ°λŠ₯을 μ‚¬μš©ν•˜μ—¬, μ•žμ„œ λ§Œλ“  index λ°°μ—΄μ˜ 처음 35개λ₯Ό input_arr와 target_arr에 μ „λ‹¬ν•˜μ—¬ λžœλ€ν•˜κ²Œ 35개의 μƒ˜ν”Œμ„ ν›ˆλ ¨ μ„ΈνŠΈλ‘œ λ§Œλ“€μ—ˆλ‹€. 그리고 λ‚˜λ¨Έμ§€ 14개λ₯Ό ν…ŒμŠ€νŠΈ μ„ΈνŠΈλ‘œ λ§Œλ“€μ—ˆλ‹€.

 

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()

 

 

νŒŒλž€μƒ‰μ΄ ν›ˆλ ¨ μ„ΈνŠΈμ΄κ³  주황색이 ν…ŒμŠ€νŠΈ μ„ΈνŠΈμ΄λ‹€. μ–‘μͺ½μ— 도미와 λΉ™μ–΄κ°€ λͺ¨λ‘ 잘 μ„žμ—¬ μžˆλŠ” 것을 확인할 수 μžˆλ‹€. 이제 λͺ¨λΈμ„ λ‹€μ‹œ ν›ˆλ ¨μ‹œμΌœλ³΄μž.

 

 

두 번째 λ¨Έμ‹ λŸ¬λ‹ ν”„λ‘œκ·Έλž¨

 

μ•žμ—μ„œ λ§Œλ“  ν›ˆλ ¨ μ„ΈνŠΈμ™€ ν…ŒμŠ€νŠΈ μ„ΈνŠΈλ‘œ k-μ΅œκ·Όμ ‘ 이웃 λͺ¨λΈμ„ ν›ˆλ ¨μ‹œμΌœλ³΄μž. fit() λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•  λ•Œλ§ˆλ‹€ KNeighborsClassifier 클래슀의 κ°μ²΄λŠ” 이전에 ν•™μŠ΅ν•œ λͺ¨λ“  것을 μžƒμ–΄λ²„λ¦°λ‹€. 이전 λͺ¨λΈμ„ κ·ΈλŒ€λ‘œ 두고 μ‹Άλ‹€λ©΄ μƒˆλ‘­κ²Œ 객체λ₯Ό λ§Œλ“€μ–΄μ•Ό ν•˜μ§€λ§Œ, μ—¬κΈ°μ„œλŠ” λ‹¨μˆœν•˜κ²Œ κ·ΈλŒ€λ‘œ μ‚¬μš©ν•œλ‹€.

 

인덱슀λ₯Ό μ„žμ–΄ λ§Œλ“  train_inputκ³Ό train_target으둜 λͺ¨λΈμ„ ν›ˆλ ¨μ‹œν‚€κ³ , 이 λͺ¨λΈμ„ ν…ŒμŠ€νŠΈν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

 

kn = kn.fit(train_input, train_target)
kn.score(test_input, test_target)

1.0

 

100%의 μ •ν™•λ„λ‘œ ν…ŒμŠ€νŠΈ μ„ΈνŠΈμ— μžˆλŠ” λͺ¨λ“  생선을 λ§žμΆ”μ—ˆμŒμ„ 확인할 수 μžˆλ‹€. 

 

 

(정리) ν›ˆλ ¨ λͺ¨λΈ 평가

 

λͺ¨λΈμ„ ν›ˆλ ¨ν•  λ•Œ μ‚¬μš©ν•œ λ°μ΄ν„°λ‘œ λͺ¨λΈμ˜ μ„±λŠ₯을 ν‰κ°€ν•˜λŠ” 것은 정닡을 미리 μ•Œλ €μ£Όκ³  μ‹œν—˜μ„ λ³΄λŠ” 것과 κ°™λ‹€. κ³΅μ •ν•˜κ²Œ ν‰κ°€ν•˜κΈ° μœ„ν•΄μ„œ,  ν›ˆλ ¨ 데이터λ₯Ό ν›ˆλ ¨ μ„ΈνŠΈμ™€ ν…ŒμŠ€νŠΈ μ„ΈνŠΈλ‘œ λ‚˜λˆ„μ—ˆλ‹€. 그런데 ν…ŒμŠ€νŠΈ μ„ΈνŠΈλ₯Ό λ¬΄μž‘μ • λ‚˜λˆ„λ©΄ μƒ˜ν”Œλ§ 편ν–₯이 일어날 수 있기 λ•Œλ¬Έμ— 도미와 λΉ™μ–΄λ₯Ό 골고루 μ„žμ–΄ λ‚˜λˆ„λŠ” μž‘μ—…μ„ ν–ˆλ‹€. μ΄λ•Œ 파이썬의 닀차원 λ°°μ—΄ 라이브러리인 λ„˜νŒŒμ΄λ₯Ό μ‚¬μš©ν•˜μ˜€λ‹€. 이 μ±•ν„°μ—μ„œλŠ” λ„˜νŒŒμ΄μ˜ shuffle() ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ λ°°μ—΄μ˜ 인덱슀λ₯Ό μ„žμ—ˆλ‹€. 

 

 

 

좜처 : λ°•ν•΄μ„ , ν˜Όμž κ³΅λΆ€ν•˜λŠ” λ¨Έμ‹ λŸ¬λ‹+λ”₯λŸ¬λ‹, ν•œλΉ›λ―Έλ””μ–΄, 2021