본문 바로가기
Python ML, Deep Learning

Python 머신러닝 #분류하기 (K-최근접 이웃#2)

by IT`s닝겐 2021. 4. 21.

안녕하세요 IT`s닝겐입니다.

 

이전 글 K-최근접 이웃#1에 이어 진행하도록 하겟습니다.

이번 진행은 기존 생선데이터를 Numpy배열로 변환 한 뒤, 그 데이터를 분리하여, 각 훈련 데이터와, 테스트 데이터로 분리하고 K-최근접 이웃을 통해 훈련하고, 평가해보며, 임의의 데이터에 대한 산점도를 찍어 K-최근접 이웃이 어떠한 데이터를 참고하는지 확인해보록 하겠습니다.

 

1. 과정 

 - 기존 Bream, Smelt생선 데이터를 무게와 길이 별로 합칩니다.

 - 합쳐진 데이터를 기존과 동일하게 (길이, 무게)인 2차원 배열로 변환하고, Bream과, smelt에 대한 target 데이터를 생성합니다.

 - 생성된 2차원 배열데이터와 타겟데이터를 Numpy 배열로 변환하고, numpy의 random.shffle 메서드를 활용 하여, 49에 대한 랜던값을 생성하여, index에 저장합니다.

 - 생성된 49개의 index배열데이터를 가지고, 변환된 numpy 생선데이터 배열의 인덱스로 사용하여, 데이터를 랜덤하게 훈련데이터와 테스트 데이터로 분리합니다.

 - 이후 K-최근접 이웃 알고리즘으로 훈련데이터를 활용하여 훈련하고, 테스트 데이터로 평가하도록합니다.

 - 훈련데이터와, 테스트 데이터에 대한 산점도를 그려봅니다.

 - 임의의 데이터를 가지고 산점도에 표현하여 K-최근접 이웃이 어떠한 데이터를 참고하는지 확인합니다.

 

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]

 

# 준비된 생선데이터를 길이, 무게 별로 합칩니다.

length = bream_length + smelt_length

weight = bream_weight + smelt_weight

 

# 합쳐진 길이, 무게 데이터를 2차원 배열로 변환하며, bream은 '1' Smelt는 '0'으로 생선의 타겟데이터를 생성합니다.

fish_data = [[l, w] for l, w in zip(length, weight)]

fish_target = [1]*35 + [0]*14

 

# 2차원 배열의 생선데이터와, 새로 생성된 생선타겟데이터를 numpy 배열로 변환

import numpy as np

input_arr = np.array(fish_data)

target_arr = np.array(fish_target)

 

# 생선데이터 총 갯수에 맞쳐 index배열 생성, 이 index배열을 random.shuffle 메서드를 이용하여, randum데이터 생성

index = np.arange(49)

np.random.shuffle(index)

 

# 생선데이터의 일부를 random한 index배열의 값을 인덱스로 활용하여, random한 훈련데이터 생성(35)

train_input = input_arr[index[:35]]

train_target = target_arr[index[:35]]

 

# 생선데이터의 일부를 random한 index배열의 값을 인덱스로 활용하여, random한 테스트데이터 생성(14)

test_input = input_arr[index[35:]]

test_target = target_arr[index[35:]]

 

# 사이킷런의 K-최근접 이웃 

from sklearn.neighbors import KNeighborsClassifier

kn = KNeighborsClassifier()

kn = kn.fit(train_input, train_target)

print(kn.score(test_input, test_target))

 

# 평가 값을 1.0으로 100프로의 평가 율을 가지고있습니다. 당연한 결과 입니다. 생선데이터와 타겟이터가 동일한 인덱스 값으로 움직였기에, 35개와 14개를 랜덤하게 나누었지만 결과적으론 같은데이터를 그냥 섞었을뿐이기 때문입니다.

 

# 임의 데이터 길이 25, 무게 150 데이터의 거리값 확인

distances, indexes = kn.kneighbors([[25, 150]])

 

# 산점도 그리기

import matplotlib.pyplot as plt

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') # K-최근접 이웃 알고리즘의 Knightbors 메서드를 사용하여 얻은 인덱스 값으로, 타겟데이터에 가까운 데이터 5개를 마름모로 표기

# plt.xlim((0, 1000)) # 축을 임의로 정의 

plt.xlabel('length') # xlabel 내용 표기

plt.ylabel('weight') # ylabel 내용 표기

plt.show() # plt.데이터 출력

 

 

4. 결과

 - 위 산점도를 볼때 임의 데이터는 삼각형 모양의 노란 점이고, K-최근접이웃에 알고리즘에(기본값: 5) 따라 최근접 데이터 5개를 녹색으로 표기하였습니다.

 - 앞서 생선데이터에 대한 산점도를 그려봤을때, 왼쪽하단의 경우 Smelt데이터가 존재하엿으며, 우측 상단으로 Bream에 대한 데이터가 많이 분포했었습니다. 그림상으로 볼 때 길이 25에 무게 150인 데이터는 Bream에 더 근접한것으로 보여집니다.

 - 이처럼 머신러닝은 준비된 데이터가 있다면, 머신러닝을 통해 학습하고, 평가하여, 임의의 데이터에 대한 분류나 예측을 할 수 있습니다.

 - 즉, 기존 코딩의 경우 데이터가 입력이되고, 그 고유에 값들이 항상 업데이트가 이루어져야지만, 추가된 데이터에 대한 결과를 얻을 수 있는반면, 머신러닝의 경우 데이터를 통학 학습으로, 새로운 데이터에 대한 결과를 예측하거나, 분류 할수 있음을 의미합니다.