본문 바로가기
Programming/Python

[ML] KN 분류 알고리즘 (기본편)

도미(35 data), 빙어(14 data) 를 분류하는 예제이다.

 

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.xlabel('length')
plt.ylabel('weight')
plt.show()

bream(도미) data

plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

smelt(빙어) data 오렌지색을 기존에서 추가.

 

 

* feature = data's feature

머신러닝은 알아서 종류를 구별해야한다. 일단 항목별로 데이터 합치고, 머신러닝에 맞게 리스트를 만든다.

length = bream_length+smelt_length
weight = bream_weight+smelt_weight   # 데이터 합침!

fish_data = [[l, w] for l, w in zip(length, weight)]  
# zip: 각각 데이터 묶어서 리스트 만듦, for로 반복해서 끝까지 하게끔(list comprehanstion)

print(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]]

 

 

머신러닝 Target data(학습자료 정답지) 만들기

fish_target = [1]*35 + [0]*14  # 차례대로 도미 데이터 35개, 빙어 데이터 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]

 

찾으려는 대상을 보통 1로 둔다. 여기서는 도미가 찾으려는 대상이기에 1로 두었다.

KNeighbors: 근방 데이터를 보고 다수결에 따른 정답을 사용하는 알고리즘.

from sklearn.neighbors import KNeighborsClassifier #알고리즘 import
kn = KNeighborsClassifier()    # 객체형성.  default: 주변 5개 데이터 참조 설정
kn.fit(fish_data, fish_target)   # fit()로 학습
kn.score(fish_data, fish_target)  # model 평가 함수 score()로 백분율단위 결과 확인.

1.0

 

score() in [0, 1]:   0은 모두 틀렸다. 1은 모두 정답이다 의미.  여기선 모두 정답을 맞춤 (정확도 100% model)

 

 

그럼 새 데이터 입력시 이 알고리즘이 제대로 작동하는 경우를 보자

아래에 새로운 [30, 600]의 data가 기존 data에 추가되었다.

plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.scatter(30, 600, marker='^') # new data as triangle form added
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

Kn이 잘 파악하는지 predict()를 써서 확인해본다.

kn.predict([[30, 600]])

array([1])               <- 제대로 예측함. (삼각형 주위에 도미 데이터가 많으니 도미라고 판단됨)

 

 

KN 알고리즘 단점: 데이터 多 -> 메모리가 많이 필요 & 직선 거리 계산에 많은 시간 필요 -> 사용 어려움

 

 

kn49 = KNeighborsClassifier(n_neighbors=49)  # 주변 참조 데이터 개수 = 49개
kn49.fit(fish_data, fish_target) # 학습
kn49.score(fish_data, fish_target) # 정확도 평가

0.7142857142857143   <- 49개로 하니 정확도가 떨어짐. (35/49) 값과 동일.

 

 

 

 

n이 몇일 때 정확도가 100에서 떨어지나 확인해보자.

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)
    # 100% 정확도에 미치지 못하는 이웃 개수 출력
    if score < 1:
        print('n = ', n, 'and the score = ', score)
        break

n =  18 and the score =  0.9795918367346939

 

n >=18 부터 score < 100 이 성립한다.

 

 

 

 

그러나 현재까지작업한 이 예제는 훈련데이터만 가지고 그 결과를 100% 도출한 것, 즉 답지를 보고 문제를 푼 모형이다.

그러므로  전체 데이터에서 training set, test set로 나눠서 traning 후 test에 시도해야한다.

 

이걸 나눌때 Sampling bias를 주의한다. (ex> training에 도미만 있으면 빙어가 test set이 되어 정확도 0이 나온다.)

 

-> numpy로 sample을 잘 섞어줘야 함 -> data에 index 배정 후 무작위로 섞어주는 방법 사용

 

 

 

 

 

import numpy as np

input_arr = np.array(fish_data)   #np사용작업 위한 array(행렬)로 변환
target_arr = np.array(fish_target)

np.random.seed(42) # 지정 랜덤함수 42번(보통 ML에서는 사용 안함. 학습용)
index = np.arange(49)  # 0에서부터 48 부여할 인덱스 생성. np.arragne(시작, 끝, 간격;실수 可)
np.random.shuffle(index)  # 섞기

train_input = input_arr[index[:35]]   # index 반영
train_target = target_arr[index[:35]] # train 지정

test_input = input_arr[index[35:]]    # index 반영
test_target = target_arr[index[35:]]  # test 지정


import matplotlib.pyplot as plt  # 그림을 그려보자

plt.scatter(train_input[:, 0], train_input[:, 1]) # 전체행, 0열(1열) & 전체행, 1열 출력
plt.scatter(test_input[:, 0], test_input[:, 1]) # 전체행, 0열(1열) & 전체행, 1열(2열) 출력
#첫 행은 length, 두번째 행은 weight이므로 각각을 x, y 좌표로 지정하였다.

plt.xlabel('length')
plt.ylabel('weight')
plt.show()

blue = training,&nbsp; orange = test&nbsp; 둘다 랜덤하게 섞여서 잘 분류되었다.

(!) Matix indexing

input_arr[[1,3]] # 2번째와 4번째의 것을 선택, 배열(array) indexing
input_arr[1,3] # 2행 4열 값을 선택

 

 

다시 KN 머신러닝을 재학습해보자.

 

 

kn = kn.fit(train_input, train_target)  # 학습
kn.score(test_input, test_target)  # 정확도 평가

1.0

 

predict 함수로 test input을 예측해보자

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

 

 

100% 일치!

 

 

 

 

 

 

 

하지만 이 머신러닝 구성과정은 하자가 많다. 실전편에서 다 갈아엎을거임

 

728x90
반응형