본문 바로가기

Machine Learning_모델설계_Python

kNN_2 분류 실습

안녕하세요 배도리 입니다. 오늘은 kNN 분류를 직접 실습해보는 시간을 갖겠습니다. 개념을 아는것도 중요하지만 직접 코드를 작성해보고 결과를 확인하는것 또한 중요하다고 생각합니다. 저는 운동을 좋아해서 운동 관련 지식들을 책이나 유튜브를 통해서 정보를 얻은 후에 헬스장으로 달려가 제가 직접 시도합니다. 물론 처음에는 어색하고 어렵지만 계속 두드리다보면 어느새 그 동작이나 자세는 저의 루틴에 포합됩니다. 그렇게 배운 여러 자세나 운동들을 정말 꾸준히 하다보면 결국 저는 강해지더라구요. 몸처럼 데이터 분야에 강해지기 위해 kNN 분류 또한 두드려보겠습니다. knnock knnock~

 

 

기계학습 분류문제 해결의 일반적 실습순서

데이터셋 불러오기 

 

데이터셋 카테고리 실수화

 

데이터 분할 학습데이터와 테스트 데이터로 나누기

 

④ 입력데이터의 표준화(필요할 경우 수행)

 

결과 분석(테스트데이터 이용) 

 

 

 

이 순서를 적용해서 실습을 진행하겠습니다!

 

 데이터셋 불러오기 

실습데이터는 seaborn 라이브러리 사용하여 Iris 데이터셋을 사용하겠습니다. iris 데이터는 붓꽃 데이터로 꽃잎의 각 부분의 폭과 길이 등을 측정한 데이터입니다. 150개의 행과 5개의 열로 이뤄져있습니다.(첫번째 필드는 순서를 표시하는 인덱스이므로 분석에서 제외) 입력변수(X)는 2~5번째 필드이고 목표(종속)변수(Y)는 6번째 필드 입니다. (Species, Class label)

seaborn라이브러리의 iris 데이터

 

seabron 라이브러리는 시각화 라이브러리로 matplotlib 기반이며 통계데이터 시각화 라이브러리입니다. 계 분석결과를 시각화하기 위한 유용한 고급 인터페이스 제공하고 약간의 변수와 파라미터 조정만으로 쉽게 그래프를 표현할 수 있도록 도와주는 도구입니다.

import seaborn as sns #seaborn을 불러오고 네임스페이스를 sns로
iris = sns.load_dataset('iris') #iris라는 변수명으로 Iris 데이터셋 download
print(iris.head())

 

iris 데이터의 type, shape, dtype을 확인합니다.

type(iris)
pandas.core.frame.DataFrame
 
iris.shape
(150, 5)
 
iris.dtypes
sepal_length float64
sepal_width float64
petal_length float64
petal_width float64
species object dtype: object

흠... dtype에서 species가 object 형식이네요 다음에 이건 바쭤야겠습니다.

 

 

seaborn 라이브러리를 사용하여 iris 데이터셋의 산점도 행렬(pairplot)을 그려보겠습니다.

import seaborn as sns #seaborn 불러옴
sns.set()
sns.pairplot(iris,hue='species',height=2.5)
#height: 그림 크기
#: 'species' 열을 기준으로 데이터를 구분하여 색상을 입힙니다.
#hue 매개변수에 지정된 열의 고유한 값에 따라 다른 색상이 할당되어 데이터 포인트가 표시됩니다.
#pairplot(산점도 행렬) 산점도행렬은 여러 변수간의 관계를 한눈에 파악할 수 있습니다.

iris 데이터셋의 산점도 행렬(pairplot)

 

 

 

 데이터셋 카테고리 실수화

왜 실수화를 진행할까요? 왜냐하면 대부분의 머신러닝 알고리즘이 숫자형 입력을 요구하기 때문입니다. 호호 그렇다면LabelEncoder 클래스를 이용하여 데이터셋의 카테고리 실수화를 진행하겠습니다. LabelEncoder 클래스는 scikit-learn 라이브러리에서 제공하는 도구로, 범주형 라벨(데이터셋 내의 변수들 중 범주형 자료를 의미)을 정수로 변환하는데 사용됩니다. 이 클래스는 주로 머신러닝 모델에 입력 데이터를 제공하기 전에 데이터를 전처리하는 과정에서 활용됩니다. LabelEncoder를 사용하면, 범주형 변수들을 간단하게 숫자로 인코딩할 수 있습니다.

이전에 데이터 전처리 게시글에서 배운 DictVectorizer 클래스의 one-hot encoding 방법과 유사해보입니다. 하지만
LabelEncoder와 DictVectorizer의 차이점은 LabelEncoder는 범주형 라벨을 정수로 변환하는 반면, DictVectorizer는 범주형 자료를 one-hot encoding을 통해 실수 벡터로 변환합니다. 또한 LabelEncoder는 각 범주에 대해 고유한 정수 값을 할당하는 반면, DictVectorizer각 범주에 대해 고유한 이진 벡터를 생성합니다.

 

 

실습자료에서 제가 흠 거리면서 바꿔야겠다고 했는데 여기서 이제 시작하겠습니다. 우선 X와 y를 분리해보겠습니다.

print(iris.shape) #iris data의 행과 열의 수

X = iris.drop('species', axis=1) #'species'열을 drop하고 input X를 정의함
# axis=1은 제 게시글"Numpy_2 배열 연산, 장단점"에서 설명드렸습니다.
 
print(X.shape)
y = iris['species']  
 
(150, 5) # 원래데이터 셋
(150, 4) # X 데이터 셋

 

분리해놓은 y도 확인해볼까요

import pandas as pd
pd.DataFrame(y)

뽑아온 y

 

X도 볼게요

X
 

남겨진 X

 

준비가 끝났습니다. 이제  scikit-learn 라이브러리의 LabelEncoder를 사용하여 iris 데이터셋의 'species' 열의 문자열 레이블을 정수로 변환하겠습니다.

from sklearn.preprocessing import LabelEncoder
import numpy as np
classle=LabelEncoder()  # LabelEncoder 클래스의 인스턴스를 생성하고, 이를 classle 변수에 저장합니다.
 
y=classle.fit_transform(iris['species'].values) # iris 데이터셋의 'species' 열의 값을 가져와서, LabelEncoder를 사용해 정수 레이블로 변환합니다. 변환된 레이블은 y 변수에 저장됩니다.
print('species labels:', np.unique(y)
#중복되는 y값을 하나로 정리하여 출력 즉, 변환된 정수 레이블의 고유한 값들을 출력합니다
 
species labels: [0 1 2]

 

원래의 species 문자열로 복원도 가능합니다. 

yo=classle.inverse_transform(y
print('species:', np.unique(yo))
 
species: ['setosa' 'versicolor' 'virginica']

 

 

 

 데이터 분할 학습데이터와 테스트 데이터로 나누기

 

전체 데이터셋을 학습(train) 데이터와 시험(test) 데이터로 나누어, 모델을 학습시키고 평가하는 과정에서 서로 겹치지 않도록 합니다. 이렇게 함으로써 모델이 학습 데이터에 과적합(overfitting)되는 것을 방지하고, 실제 세계의 데이터에 대한 모델의 성능을 측정할 수 있습니다. 학습 데이터 모델을 학습시키기 위해 사용됩니다. 시험 데이터는 모델의 일반화(generalization) 성능을 평가하는 데 사용됩니다. 학습 데이터와 시험 데이터의 분할 비율은 문제의 성격과 데이터셋의 크기에 따라 다를 수 있으며, 일반적으로 70:30, 80:20 또는 75:25와 같은 비율로 나눕니다. 

 

코드도 진행해보겠습니다. scikit-learn의 train_test_split 함수를 사용하여 입력변수(X)와 종속변수(y)로 이루어진 데이터를 학습 데이터와 테스트 데이터로 나누겠습니다.

from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y, test_size=0.3, random_state=1, stratify=y)
 
#random_state=1: 재현 가능한 결과를 위해 난수 생성기의 시드 값을 1로 설정합니다.
#stratify=y 계층화 기능을 사용하여 클래스의 비율을 유지하면서 데이터를 나눕니다. 이는 불균형한 데어테셋에서 유용합니다. 이를 사용한다면 불균형한 클래스 분포를 가진 데이터셋에서 학습 데이터와 테스트 데이터를 나눌 때, 각 데이터셋에 클래스 비율이 원본 데이터셋과 유사하게 유지됩니다.
#계층화(stratification) 기능을 사용하면, 각 클래스의 샘플 비율이 학습 데이터와 테스트 데이터에서도 일정하게 유지됩니다.
# shuffle: split을 수행하기 전에 데이터를 섞을 것인지의 여부 (default = True)
 
print('입력변수(학습데이터)    : ',  X_train.shape)
print('입력변수(테스트데이터)  : ', X_test.shape)
print('종속변수(학습데이터)    : ',  y_train.shape)
print('종속변수(테스트데이터)  : ', y_test.shape)
 
입력변수(학습데이터) : (105, 4)
입력변수(테스트데이터) : (45, 4)
종속변수(학습데이터) : (105,)
종속변수(테스트데이터) : (45,)

 

 

이제 드디어 kNN을 데이터에 적용시켜보겠습니다. 코드에서 scikit-learn의 KNeighborsClassifier를 사용하여 k-최근접 이웃(k-Nearest Neighbors,kNN) 알고리즘을 적용하겠습니다.

 

 

from sklearn.neighbors import KNeighborsClassifier  #KNN 불러오기.

knn = KNeighborsClassifier(n_neighbors=5, p=2
# n_neighbors=5: k 값으로 5를 설정하여 주어진 데이터 포인트에 대해 가장 가까운 5개의 이웃을 찾습니다.
# 기본값은 p=2이므로, 유클리디안 거리를 기본 거리 측정 기준으로 사용합니다.
# p=1 맨허튼 거리
# p=2 유클리드 거리
# p > 2: Minkowski 거리를 사용합니다. 여기서 p 값에 따라 거리 측정 방식이 조정됩니다.

knn.fit(X_train,y_train) #kNN 분류기를 학습 데이터(X_train, y_train)에 맞추어 학습시킵니다. 모델 fitting과정
 
 
KNeighborsClassifier()

학습이 완료됐습니다!

 

 

이후 kNN 알고리즘을 사용하여 학습 데이터와 테스트 데이터의 종속 변수(y) 값을 예측하고, 오분류된 샘플의 개수를 계산하겠습니다.

y_train_pred = knn.predict(X_train) #train data의 y값 예측치
#: 학습 데이터의 입력변수(X_train)를 사용하여 종속 변수(y) 값을 예측하고, 예측된 결과를 y_train_pred 변수에 저장
y_test_pred  = knn.predict(X_test)  #모델을 적용한 test data의 y값 예측치
 
print('Misclassified training samples: %d' %(y_train!=y_train_pred).sum()) #학습데이터로 오분류 갯수 확인
#%d: 정수를 나타내는 서식 지정자입니다. 이를 사용하면, 정수 값을 문자열에 삽입할 수 있습니다.
print('Misclassified test samples: %d' %(y_test!=y_test_pred).sum()) #테스트데이터로 오분류 갯수 확인
 
Misclassified training samples: 2
Misclassified test samples: 1

 

정확도도 한번 계산하겠습니다.

from sklearn.metrics import accuracy_score #정확도 계산을 위한 모듈 import
print(accuracy_score(y_test,y_test_pred))  #45개 test sample중 44개가 정확하게 분류됨
 
0.9777777777777777

 

 

 

이처럼 정확도를 구했지만 분류 문제평가 방법마다 장단점 존재하기 때문에 회귀 분석과 달리 다양한 성능 평가 기준(metric)이 필요합니다. 다음 게시글에서 결과분석과 표준화에 대해 설명하겠습니다!

'Machine Learning_모델설계_Python' 카테고리의 다른 글

kNN_4 회귀  (0) 2023.05.14
kNN_3 분류 실습(표준화, 결과분석)  (3) 2023.05.13
kNN_1 분류  (2) 2023.05.09
기계학습(Machine Learning) 방법론  (2) 2023.05.08
데이터 전처리_3  (0) 2023.05.07