[머신러닝] KNN으로 데이터 분류하기 (with Scikit-Learn)
공부/코딩

[머신러닝] KNN으로 데이터 분류하기 (with Scikit-Learn)

 

[Pandas] 6. 폴더 내 여러 데이터 프레임(파일) 합치기

[Pandas] 5. 조건에 맞춰 데이터 추출하고 수정하기 (Kaggle 에서 가져온 Gear Defection 데이터 이용) Kaggle 이라는 사이트가 있습니다. 데이터 사이언스 커뮤니티입니다. 유명한 IT 기업들이 데이터 분석

senti-mech.tistory.com

 앞선 글에서 각 Defection 별로 나뉘어져있던 변위 데이터를 한 곳으로 모았다. 이 데이터를 이용하면 새로운 값을 넣었을 때, 그 것이 어떤 Defection인지 예측하는데 도움이 될 수 있다. 하지만 Defection 당 데이터가 150,000개다. 너무 많다.

 

 그래서 나는 머신러닝을 사용해보기로 했다. 머신러닝 분류 모델에는 여러가지가 있다. 나이브 베이즈, Decision Tree, Support Vector Machine (SVM), Random Forest 등. 나는 그 중에서도 K-Nearest Neighber (KNN)을 사용해볼 것이다. 이 다음 글에선 SVM을 사용하여 차이를 비교해볼 예정이다.

 

 

KNN (K-Nearest Neighbor) 개념

KNN

velog.io

 위 글은 내가 찾아본 KNN 관련 글 중에 가장 정리가 잘 되어 있는 글이다. 이 글에서 진행할 실습도 윗 글의 다음 글을 많이 참고 하였으니 꼭 한 번 보시길. 아래는 요약이다.

  • KNN은 주변의 데이터를 통해 분류하는 모델이다.
  • 이 때 '주변'을 어느 정도로 판단할 것인지가 문제다. 주변이 너무 작으면 Overfitting, 너무 크면 Underfitting 이다.
  • 데이터는 정규화를 거치는게 좋다. 각 데이터의 절대값이 달라 알고리즘에 반영될 때 문제가 될 수 있기 때문이다.

1. KNN 체험해보기

from sklearn.neighbors import KNeighborsClassifier # sklearn에서 KNN모듈 불러오기
classfier = KNeighborsClassifier(n_neighbors = 1) # 모델 생성. 주변 몇 개의 데이터를 참고할 것인가?

 

 n_neighbors 는 일반적으로 k라고 부른다. 앞서 말한 주변의 범위다. k 값이 너무 작으면 Overfitting (사소한 것에 영향을 너무 많이 받음), k값이 너무 크면 Underfitting (다 비슷하게 보므로 분류가 힘듦)이다. 나는 여기서 예시를 보여주기 위해 k=1로 설정하였다.

 

training_points = [
    [1, 1, 1],
    [3, 3, 3],
    [4, 4, 4]
] # 가지고 있는 데이터 입력.

training_labels = ['a','b','c'] # 가지고 있는 데이터의 종류

classfier.fit(training_points, training_labels) #학습

 

 임의의 데이터를 입력한 후, 각 데이터에 라벨링을 하여 학습시켰다.

 이제 랜덤 데이터를 넣어서 확인해보자.

unknown_points = [
    [0,0,0],
    [2.5,2.5,2.5],
    [5,5,5],
    [2,2,2]
]

guesses = classfier.predict(unknown_points)
guesses

 주변의 한 개를 보고 판단하는 모델이다. [0,0,0]은 [1,1,1]이 가장 가까우므로 a가 나왔다. 다른 좌표들도 동일한 방식으로 분류되었다. 그런데 [2,2,2] 는 [1,1,1] 과 [3,3,3] 사이 정중앙이다. 이 때 값은 a가 나왔다. 아마 시스템 내 판단기준이 있는 것으로 보인다. (여러번 시도해도 a 가 나온다.)

 

 이제 해야할 것은 training points 에 변위 데이터를 넣고, 각 Defection으로 라벨링 하는 것이다. 간단하다. 근데 이렇게 학습시킨 모델의 신뢰성을 알 수가 없다. 어떻게 검증할 수 있을까?

 

2. 실제 데이터로 KNN 사용해보기

import pandas as pd
import numpy as np

data = pd.read_csv('total.csv')

displacement = data[['sensor1','sensor2']]
defection = data.iloc[:,-1]

 

 x축 변위와 y축 변위 데이터를 displacement 라는 데이터프레임에 넣었고, 데이터 마지막 열에 있는 defection 종류도 입력해주었다. iloc[행위치, 열위치] 이며 : 는 전체라는 걸 기억하자.

 

from sklearn.model_selection import train_test_split

train_data, test_data, train_labels, test_labels = train_test_split(displacement, defection, test_size = 0.2, random_state = 2024)

print(len(train_data)) #결과 120000

 

 총 150,000개의 데이터를 모두 학습시킨다고 가정해보자. 기존의 데이터 하나를 뽑아 완성된 모델을 테스트한다면 적절할까? 아니다. 우리는 학습되지 않은 데이터로 테스트 했을 때, 올바른 결과가 나와야 정상이다. 아는 걸 알도록 가르치는게 아니라, 모르는 걸 예측하는 모델을 만드는 것이기 때문이다.

 

 그래서 나는 train_test_split 라는 함수를 사용했다. data에는 변위 데이터를, labels에는 결과 데이터를 넣어주었다.

test_size 는 데이터를 몇대 몇으로 학습과 시험 데이터를 나누는지 결정하고, random_state는 세트를 나눌 때 무작위성을 도와줄 난수를 넣어주는 것이다. (같은 난수는 같은 분류를 낳는다.) 나는 4:1로 하였고, train_data의 갯수가 120,000개인 것을 확인하였다.

 

from sklearn.neighbors import KNeighborsClassifier
classifier = KNeighborsClassifier(n_neighbors = 50)

classifier.fit(train_data, train_labels)
classifier.score(test_data, test_labels) # 결과값 0.5066

 

 학습 후 .score() 을 통해 정확도를 확인했다. 절반의 정확도. 그래서 k 값을 10으로 낮추었더니 0.48이 나왔고, 100으로 올렸더니 0.51이 나왔다. k 값에 따라 정확도가 달라진다. 그러면 최적의 k값은 어떻게 찾을까?


 

 반복이라고 생각해서 여러 숫자를 넣어봤는데... 비슷비슷하다. 10000까지 넣으니까 시간도 오래걸리고. 그래서 어딘가에서 조언을 받았더니 정규화(Normalizing)를 하라고 한다. 엥? 스케일 차이가 안나는데도요? 그렇다. 데이터끼리 값 차이가 거의 없기 때문에 해보라고 한다. 그리고 혹시 모르니 scatter부터 찍어보라고 한다.

 

 KNN에 내용이 좀 벗어나므로 다음 글에서...