ABC부트캠프 데이터 탐험가 과정

[20일차] ABC 부트캠프 분류(Classification)와 K-NN알고리

hwibeenjeong 2024. 7. 31. 23:53

 

1. 분류(Classification) 알고리즘

머신러닝 중 분류 기술은 지도학습 중 하나이다. 제공된 데이터를 학습하고, 학습된 모델은 데이터들을 분류한다. 분류 알고리즘 중 가장 대표적인 k-NN 알고리즘에 대해 알아보자. 

 

k-NN(k-Nearest Neighbors) 알고리즘

k 최근접 이웃 알고리즘은 기준점 주변의 데이터들을 바탕으로 값이 결정된다. 먼저 범위(k)를 정해주고, 범위 내에 있는 데이터가 어떤 클래스인지에 따라 기준점의 데이터의 클래스가 결정된다.

만약 k가 3이라고 가정했다면,  빈 네모는 붉은 별로 분류된다. 하지만 반대로 k값이 증가함에 따라 데이터의 개수가 아래의 그림과 같아진다면 빈 네모는 파란 원이 된다.

이렇게 주위의 데이터들 바탕으로 값이 결정되기 때문에 최근접 이웃이라고 하는 것 같다. 

 

k-NN 알고리즘의 장점

  • 단순하고 효율적이다.
  • 기저 데이터 분포에 대한 가정을 하지 않는다.
  • 훈련 단계가 더 빠르다.
  • 수치 기반 데이터 분류 작업에서 성능이 우수하다.

위와 같은 장점이 있다.

k-NN 알고리즘의 단점

  • 모델을 생성하지 않아 특징과 클래스 간 관계를 이해하는데 제한적이다.
  • k 값의 설정이 중요하다.
  • 데이터가 많아지면 분류 단계가 느리다.
  • 명목 특징 및 누락 데이터를 위한 처리가 필요하다.

k-NN 알고리즘에 대해 알아보았으니 분류에 대한 대표적인 예시들을 확인해보자.

 

2. 붓꽃(Iris)에 대한 분류

from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
from sklearn import metrics
#라이브러리 호출

iris = load_iris() # sklearn 라이브러리 내장 데이터인 iris호출

iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)
# iris의 독립변수를 데이터프레임에 저장, 레이블을 iris의 feature_name으로 설정
iris_df['target'] = pd.Series(iris.target)
# iris의 종속변수를 데이터프레임에 추가

x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target , test_size = 0.2) # 훈련 데이터와 예측 데이터를 분류
# 종속변수와 독립변수를 train, test 영역으로 분리

k=7
# 이웃의 수 지정
knn = KNeighborsClassifier(n_neighbors=k)
# knn 알고리즘의 생성자를 이용하여 객체 생성, 속성 값을 인자로 전달

knn.fit(x_train, y_train) # 모델 객체를 학습

y_predicts = knn.predict(x_test) # 학습된 모델을 통해 x_test를 바탕으로 결괏값 예측

classes = {0:'SETOSA', 1: 'VESICOLOR', 2:'VIGINICA'} # iris의 종류를 클래스로 변환
found_new_iris = np.array([[4.0, 2.0, 1.3, 0.4]]) # 임의의 iris 생성
index = knn.predict(found_new_iris) # 임의의 iris의 종류를 예측

score = metrics.accuracy_score(y_test, y_predicts) # 정확도 계산

 

3. 닥스훈트, 사모예드에 대한 분류

import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 닥스훈트에 대한 데이터 생성
dachshund_len    = [77, 78, 88, 85, 73, 77, 73, 80]
dachshund_height = [25, 28, 29, 30, 21, 22, 17, 35]

# 사모예드에 대한 데이터 생성
samoyed_len    = [75, 77, 86, 86, 79, 83, 83, 88]
samoyed_height = [56, 57, 50, 53, 60, 53, 49, 61]

# 닥스훈트와 사모예드 데이터를 바탕으로 산포도 그리기
plt.scatter(dachshund_len, dachshund_height, c = 'red', marker = '+', label = 'Dachshund')
plt.scatter(samoyed_len, samoyed_height, c = 'blue', marker = '*', label = 'Samoyed')
plt.xlabel('Length')           # x축은 길이
plt.ylabel('Height')           # y축은 높이
plt.title('DOG SIZE')          # 표의 이름을 'Dog Size'로 설정
plt.legend(loc = 'upper left') # 산점도에 대한 설명을 좌측 상단으로 설정
plt.show()                     # 표 출력

# 예측하고자 하는 강아지 데이터 생성
new_dog_len    = [79] 
new_dog_height = [35]

# 닥스훈트 데이터의 행렬변환
dachshund_data = np.column_stack((dachshund_len, dachshund_height))
dachshund_label = np.array([0,0,0,0,0,0,0,0])

# 사모예드에 대한 행렬변환
samoyed_data = np.column_stack((samoyed_len, samoyed_height))
samoyed_data_label = np.ones(len(samoyed_data))

# 예측을 위한 강아지 데이터를 배열로 변환
new_dog_data = np.array([[79, 35]])

# 닥스훈트와 사모예드에 대한 데이터를 병합
dogs_data = np.concatenate((dachshund_data, samoyed_data), axis = 0)
# 닥스훈트와 사모예드에 대한 레이블을 병합
dogs_label = np.concatenate((dachshund_label, samoyed_data_label))

k = 5 # 근접한 이웃 수 설정
knn = KNeighborsClassifier(n_neighbors=k) # k-NN알고리즘 객체 생성
knn.fit(dogs_data, dogs_label) # 모델 학습
y_predict = knn.predict(dogs_data) # 학습된 모델로 dogs_data를 예측
predict_new_dog = knn.predict(new_dog_data) # 예측하고자 하는 강아지를 분류

# 강아지 클래스 분류
classes = {0:'닥스훈트', 1: '사모예드'}


# 닥스훈트의 길이, 높이에 대한 평균 값 계산
dachshund_length_mean = np.mean(dachshund_len)
dachshund_height_mean = np.mean(dachshund_height)

# 닥스훈트 데이터의 평균에 기반하여 랜덤 데이터 생성
new_normal_dachshund_len_data = np.random.normal(dachshund_length_mean, 6.0, 200)
new_normal_dachshund_height_data = np.random.normal(dachshund_height_mean, 6.0, 200)

# 사모예드의 길이, 높이에 대한 평균 값 계산
samoyed_length_mean = np.mean(samoyed_len)
samoyed_height_mean = np.mean(samoyed_height)

# 사모예드 데이터의 평균에 기반하여 랜덤 데이터 생성
new_normal_samoyed_len_data    = np.random.normal(samoyed_length_mean, 6.0, 200)
new_normal_samoyed_height_data = np.random.normal(samoyed_height_mean, 6.0, 200)

# 새로 만든 닥스훈트, 사모예드에 대한 데이터를 행렬변환
new_dachshund_data = np.column_stack((new_normal_dachshund_len_data, new_normal_dachshund_height_data))
new_samoyed_data   = np.column_stack((new_normal_samoyed_len_data, new_normal_samoyed_height_data))

# 새로운 레이블 생성하기 닥스훈트는 0, 사모예드는 1로 설정
new_dachshund_label = np.zeros(len(new_dachshund_data))
new_samoed_label    = np.ones(len(new_samoyed_data))

# 총 300개의 강아지 데이터 만들기
new_dogs = np.concatenate((new_dachshund_data, new_samoyed_data))
new_labels = np.concatenate((new_dachshund_label, new_samoed_label))

# 학습 데이터, 예측 데이터로 분할
x_train, x_test, y_train, y_test = train_test_split(new_dogs, new_labels)


k = 7 # 근접한 이웃의 수 설정
knn = KNeighborsClassifier(k)     # k-NN 모델생성
knn.fit(X = x_train, y = y_train) # 생성한 모델 학습
y_predicts = knn.predict(x_test)  # 학습된 모델을 사용하여 테스트 데이터 예측

plt.plot(y_predicts, y_test, marker = '.') # 시각화
plt.show()

4. 필기체 인식에 대한 분류

4-1. 이미지 분석에 필요한 기술들

주로 이미지 데이터를 모델에 넣기 전에 배열 형태를 변경하여 모델이 입력을 쉽게 처리할 수 있도록 하는 데 사용된다. 이번 필기체 분석을 위해서 이미지의 밝기의 보수를 취해줄 것이다. 그 이유는 밝기의 보수를 취함으로써 이미지의 명암 대비를 높일 수 있습니다. 이것은 특히 손글씨 이미지에서 유용하다. 손글씨가 종종 어두운 배경에 밝게 나타나는데, 이 경우 보수를 취하면 글자가 강조되고 배경이 사라져 분석하기 더 쉬워진다. 이러한 이유로 인해 다차원 배열을 1차원 배열로 만들고, 다차원 배열의 평탄화를 진행한다.

4-2. 코드 해석

from sklearn import datasets, metrics
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import numpy as np
from sklearn.neighbors import KNeighborsClassifier

digits = datasets.load_digits() # 필기체에 대한 데이터셋 로딩

n_samples = len(digits.images)
data = digits.images.reshape((1791, -1)) # 이미지 확인

x_train, x_test, y_train, y_test = train_test_split(np.array(digits.data), digits.target, test_size = 0.3, random_state=42)
# 테스트 데이터와 학습데이터를 나누는데, random_state를 42라는 값으로 맞추어 기기별, 사용자 별 결과 값이 모두 동일하게 분리

k = 5 # 근접한 이웃의 수 
knn = KNeighborsClassifier() # knn 알고리즘 객체 생성
knn.fit(x_train, y_train)    # 분할한 데이터를 바탕으로 모델 학습

y_prediction = knn.predict(x_test) # 학습된 모델을 바탕으로 예측 

# plt.imshow(x_test[0].reshape(8,8), cmap=plt.cm.gray_r, interpolation='nearest')
# plt.show() 이미지 시각화

y_predict = knn.predict(x_test[[0]]) # 임의의 값에 대한 예측 결과를 y_predict에 할당