일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 크롤링
- JSP/Servlet
- 스마트인재개발원
- 활성화함수
- ERD
- 1차프로젝트
- randomForest
- 하이퍼파라미터튜닝
- 취업성공패키지
- 비스포크시네마
- 2차프로젝트
- 백엔드
- 오픈소스깃허브사용
- 프로젝트
- 국비지원
- 안드로이드
- intent
- 2차 실전프로젝트
- 내일배움카드
- springSTS
- KNN모델
- 취업연계
- MSE
- 손실함수
- gitclone
- semantic_segmentation
- MVCmodel
- 교차검증
- 머신러닝
- 선형모델 분류
- Today
- Total
또자의 코딩교실
[스마트인재개발원] Machine Learning - KNN 알고리즘(실습과 함께) 본문
이번 포스팅에서는 분류와 회귀에 모두 사용가능한 머신러닝의 모델인
K-최근접 이웃 알고리즘에 대해 알아보자.
K-Nearest Neighbors(KNN)
새로운 데이터 포인트와 가장 가까운 훈련 데이터셋의 데이터 포인트를 찾아 예측함.
k값에 따라 가까운 이웃의 수가 결정됨.
분류와 회귀에 모두 사용 가능함.
KNN 모델의 장단점
- 이해하기 쉬고 조정없이도 좋은 성능을 발휘함
- 많은 특성을 가진 데이터 세트와 특성 값 대부분이 0인 희소한 데이터 세트에는 잘 동작하지 않음
- 전처리 과정이 중요하고 잘 쓰이지 않음
- 거리를 측정하기 때문에 같은 scale을 같도록 정규화가 필요함
- 훈련 데이터 세트가 크면(특성, 샘플의 수) 예측이 느려짐
우선, 결정 경계에 대해 이해할 필요가 있다. 결정경계는 가져온 DATA SET들 중, 데이터가 범주형으로 분류되는 경우
산점도를 그려 데이터를 시각화 하였을 때, 비슷한 데이터들끼리의 집합을 색깔로 표시하여 경계를 그리는 식으로 DATA를 분류하는 방식으로 그려진다. 결정 경계를 정하는 기준은 k이다.
KNN모델을 직접적으로 코딩하는 데에는 Jupyter Notebook을 사용하였다.
bmi데이터를 활용하여 코딩하였다.
우선 코딩을 함에 있어 필요한 library들을 import해준다.
import pandas as pd
import matplotlib.pyplot as plt
import sklearn
!pip install scikit-learn
from sklearn.neighbors import KNeighborsClassifier
다음으로 데이터를 불러오고 boolean indexing으로 원하는 데이터만 뽑아온다.
#데이터 수집(read_csv로 간략화)
bmi = pd.read_csv("data/bmi_500.csv")
bmi
#읽어온 csv파일 확인
bmi.describe()
#Boolean인덱싱으로 원하는 데이터만 뽑아오기(선택 필터링)
bmi[bmi['Label']=='Normal']
#한번 더 리스트로 감싸 df형태로 출력함. 감싸지 않으면 series형태로 출력됨.
#데이터 분석(EDA) 및 데이터 시각화
#사용자 함수(def MyScatter)를 만들어 코드 재사용성을 높인다.
def myScatter(label, color):
temp = bmi[bmi['Label']==label] # 보고싶은 데이터만 잘라냄
#함수에 들어온 label중 normal인 데이터들을 temp에 넣는다.
plt.scatter(temp['Weight'], #x
temp['Height'], #y
label=label, #label
c=color) #색깔
#사용자 함수를 적용시켜 data를 직관적으로 봄으로서 model에 새로 데이터가 들어갔을 때 결정경계를 정한다.
myScatter('Extremely Weak', 'yellow')
myScatter('Weak', 'blue')
myScatter('Overweight', 'green')
myScatter('Extreme Obesity', 'purple')
myScatter('Obesity','red')
myScatter('Normal', 'orange')
plt.legend(loc='upper right')
plt.Xlabel=('Weight')
plt.Ylabel=('Height')
plt.show()
출력되는 산점도는 다음과 같다.
산점도 매트릭스는 DataFrame형태의 데이터를 쉽게 시각화하여 확인하기 위해 사용한다.
데이터의 시각화까지 완료했다면, 이제는 모델을 학습시키는 과정중 훈련데이터와 테스트 데이터의 분리를 진행한다.
이 과정에서 iloc를 사용해도 되고, train_test_split 함수를 사용해도 된다.
train_test_split함수는 문제데이터와 테스트데이터를 주면 자동으로 두가지로 나눠 데이터의 쏠림현상을 막기 위해 사용한다.
#모델을 학습시키기 좋게 만드는 과정
#Train data와 Test data를 분리한다.
#보통 X에서 3(Train)대 1(Test)로 나눔
X=bmi.loc[:, 'Height':'Weight'] #슬라이싱을 통해 문제를 가져옴. #독립변수
y=bmi.loc[:, 'Label'] #종속변수
X.shape, y.shape #분리가 잘 되었는지 확인하는 과정
#X문제 훈련 데이터와 테스트 데이터 분리
X_train = X.iloc[:350]
X_test = X.iloc[350:]
X_train.shape, X_test.shape
#y문제 훈련 데이터와 테스트 데이터 분리
y_train = y.iloc[:350]
y_test = y.iloc[350:]
y_train.shape, y_test.shape
이후 모델 선택 및 학습, 평가를 진행한다.
#모델 선택(Hyper Parameter 튜닝)
knn_model = KNeighborsClassifier(n_neighbors=10)
#모델 학습
knn_model.fit(X_train, y_train) #훈련용 문제와 정답을 주어서 학습시킴.
#모델 평가
# 분류 정확도 accuracy 끌어오기
from sklearn import metrics #모델 평가를 위한 모듈
#추론/예측을 진행하는 함수 predict
pred = knn_model.predict(X_test)
#모델에 test데이터를 던져주면 pred 출력값으로 컴퓨터가 예상한 예측값이 나오게 된다.
metrics.accuracy_score(pred, y_test)
#컴퓨터의 pred답안과 y_test의 정답을 비교한다.
pred = knn_model.predict(X_train)
metrics.accuracy_score(pred, y_train)
결과값은 다음과 같이 나오게 된다.
정확도가 90이 넘는다면 좋은 모델이라 판단할 수 있지만 현재 경우에는,
test data가 0.93
train data가 0.90의 퍼센트를 보이고 있다.
이 경우 배웠던 train data로 다시 model data의 test를 진행하였을 때,
train data의 정답률이 더 낮기 때문에 train data를 제대로 컴퓨터가 공부하지 못했다고 판단할 수 있다.
>> 과소적합
지금부터 모델을 활용/예측/추론하는 단계로 넘어가보자.
다음의 코드는 n-neighbors 상수를 1~15까지 여러단계로 돌려서 어떤 값을 k상수로 주었을때
가장 정확도가 높은지 판단할 수 있도록 시각화 까지 진행할 것이다.
이때 여기서 Hyper Parameter는 다음과 같다.
Parameter : 파라미터는 데이터를 통해 구해지며 모델 내부적으로 결정되는 값. 사용자에 의해 조정되지 않음.
Hyper-Parameter : 사용자가 직접 설정하면 하이퍼 파라미터, 모델 혹은 데이터에 의해 결정되면 파라미터
#모델 선택(Hyper-Parameter 튜닝)
train_acc = []
test_acc=[]
#k의 상수를 n으로 두고 n을 1부터 15까지 돌리는 코드
for n in range(1,16):
#모델 선정
knn_model = KNeighborsClassifier(n_neighbors=n)
#모델 학습
knn_model.fit(X_train, y_train)
#모델 평가
#분류 모델의 score함수는 기본적으로 accuracy score를 구한다
#train acc
train_acc.append(knn_model.score(X_train, y_train))
#test acc
test_acc.append(knn_model.score(X_test, y_test))
#나온 훈련 데이터와 테스트데이터의 정확도를 평가하기 위해 그래프로 시각화하는 코드
plt.plot(range(1,16), #X값
train_acc, #y값
label="train acc")
plt.plot(range(1,16), #X값
test_acc, #y값
label="test acc")
plt.legend() #범례 표시
plt.xlabel('neighbor number')
plt.ylabel('accuracy')
plt.show()
시각화 결과 그래프는 다음과 같다.
train data k=1일경우 acc가 100인 이유는 가장 가까운 것은 본인. 정확할 수 밖에 없다.
반대로 test data k=1 이면 test data는 결정 경계가 복잡해져 과대적합이 일어난 것을 확인할 수 있다.
train data가 복잡해지면 복잡해질수록 높은 정확률을 보여주는데 test data는 10점을 기준으로 급격히 떨어지고 있다.
test acc가 높기때문에 좋은 구간이지 않느냐? >> 해석의 여지가 있음. 주관적인 판단이 필요함.
acc=7 일 경우, train acc 와 test acc의 acc가 거의 일치하는 7의 지점이 정확도가 비교적 더 높다 얘기할 수 있음.
과소적합을 고려했을때에는 7부분이 제일 나을수도 있으며 Hyper-Parameter를 고려하면 10이 제일 좋을수도 있음.
절대적으로 완벽하게 정의할 수 있는 데이터들이 아니기 때문에 애매하다 얘기할 수 있다. 실상에 또 다른 데이터를 넣었다면 못맞출수도 있기 때문이다. 따라서 Parameter의 최적점은 7 or 10이다.
개선여지 : 데이터 전처리를 하여 acc 점수를 올리기. >> 성별을 feature에 넣어 사용
기존 성별데이터는 문자열로 되어 있어 머신러닝에서 활용이 불가능한 데이터이다.
따라서 성별데이터를 인코딩하여 활용해보자.
인코딩 : 범주형 데이터를 수치화 시키는 작업
label-incoding : 범주형으로 표기된 데이터를 숫자로 mapping시킨 형태.
하지만 0,1,2,3등의 숫자형 데이터(범주의 특성은 여전히 지속)으로 바꿔 주었을 때 컴퓨터 입장에서는 범주형 데이터가 그저 숫자일 뿐이기 때문에 연관관계가 있고 연산이 가능한 객체라 판단할 수도 있다.
다음은 라벨 인코딩 코드이다.
bmi['Gender']=bmi['Gender'].map({'Male':0, 'Female':1})
# map함수는 딕셔너리 형태로 column 자체의 데이터들을 replace한다.
# series 형태로 출력되고 int형으로 dtype이 나온것또한 확인할 수 있다.
# 데이터가 int64형으로 바뀐것은 통계에 있어 문자열사용은 연산이 불가능해
# 0과 1로 바꿔주었을뿐 수치형데이터로 바꾼것은 아니다.
# radio타입의 범주형데이터가 숫자의 형태인것
bmi
라벨 인코딩에는 딕셔너리 형태로 column자체의 데이터들을 replace하는 map함수를 이용하였다.
bmi를 출력하면 다음과 같이 기존에 문자열이었던 데이터가 0과 1로 나누어진 숫자형의 범주형데이터가 된 것을 확인할 수 있다.
그리고 라벨인코딩이 이루어진 다음, 성별데이터를 포함시켜 다시 훈련데이터와 테스트데이터를 나누고
모델에 학습시키고 정확도를 비교해보자. 데이터만 바뀌었을 분, 모델에 훈련을 진행하는 과정은 기존과 같다.
x=bmi.iloc[:,:-1] # :-1 : 마지막 컬럼을 빼고 나머지
y=bmi.iloc[:,-1] # -1 : 마지막만
x_train = x.iloc[:350]
x_test = x.iloc[350:]
y_train = y.iloc[:350]
y_test = y.iloc[350:]
train_acc_g = []
test_acc_g = []
for n in range(1, 16):
#모델 선정
#k의 상수를 n으로 두고 n을 1부터 15까지 돌리는 것
knn_model = KNeighborsClassifier(n_neighbors=n)
#6. 모델 학습
knn_model.fit(X_train, y_train)
#7. 모델 평가
# 분류의 모델의 score()는 기본적으로 accuracy 스코어를 계산
train_acc_g.append(knn_model.score(X_train, y_train))
test_acc_g.append(knn_model.score(X_test, y_test))
plt.plot(range(1, 16), train_acc_g, label="train acc gender")
plt.plot(range(1, 16), test_acc_g, label="test acc gender")
plt.legend() # 범례표시
plt.xlabel('neighbor number')
plt.ylabel('accuracy')
plt.show()
결과로 출력되는 갱신된 acc 그래프는 다음과 같다.
k=10 일 경우, 훈련데이터보다 테스트 데이터의 결과 정확도가 더 높으므로 컴퓨터가 제대로 훈련데이터들을 공부하지 못했다 판단할 수 있다.
k=7 일 경우, 거의 모든 acc가 편차 정도가 낮고 일치하기 때문에 적합한 k상수라 할 수 있다.
최종적으로 나는 KNN모델을 이해함에 있어 이런식으로 이해하였다.
KNN 상수로 지정해 주는 n-neighbors에서 k만큼의 반지름을 가지는 원 내부에서
k만큼의 반지름이 점차 증가하는 원을 그리다가 들어오는 데이터의 갯수가 k가 되면 멈추는 방식
다음 포스팅에서는 머신러닝의 근본중의 근본, iris 데이터를 활용한 KNN 분류실습에 대해 알아보자.
'코딩공부 > 머신러닝 & 딥러닝' 카테고리의 다른 글
[스마트인재개발원] 근본중의 근본) iris 데이터를 활용한 KNN 분류실습 (0) | 2021.12.08 |
---|---|
[스마트인재개발원] Kaggle 경진대회 (스압주의) (0) | 2021.12.06 |
[스마트인재개발원] 머신러닝을 통한 Kaggle 데이터 분석하기 (0) | 2021.11.29 |
[스마트인재개발원] Machine Learning - 일반화, 과대적합, 과소적합 (0) | 2021.11.24 |
[스마트인재개발원] Machine Learning - 개요 (0) | 2021.11.23 |