ESL 연구실 활동/LAB

혼공머 스터디 (1~2장)

천숭이 2022. 1. 25. 18:11
도미,  빙어 분류 문제

sklearn

k-최근점 이웃 알고리즘



# 도미 데이터(길이와 무게) 준비하기

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]
print(len(bream_weight))  # 도미데이터 35개

 

# 산점도 (scatter plot)으로 도미데이터 살펴보기

import matplotlib.pyplot as plt
plt.scatter(bream_length, bream_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

각 점이 도미 데이터

 

# 빙어 데이터(길이와 무게) 준비하기

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]
print(len(smelt_weight))  # 빙어 데이터 14개

 

# 도미와 빙어 데이터 모두 살펴보기

# scatter 메소드에 두 개의 데이터를 넣으면 색깔이 자동 지정되며 그래프 출력
plt.scatter(bream_length, bream_weight)  # 도미 (파랑색)
plt.scatter(smelt_length, smelt_weight)  # 빙어 (주황색)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

도미(파랑색), 빙어(주황색)

- 산점도를 보고 알 수 있는점 :

1. 빙어는 도미보다 크기와 무게가 작다

2. 빙어는 길이가 길어진다해도 무게가 크게 증가하지 않는다

3. 도미는 길이와 무게가 비례하다고 할 정도로 같이 커진다

4. 도미는 빙어보다 무겁고 무게가 많이 나간다

 


 

# 두 개의 length 데이터를 하나로 합친다

length = bream_length+smelt_length
weight = bream_weight+smelt_weight

 방어x 빙어o

fish_data = [[l, w] for l, w in zip(length, weight)]
# [[25.4, 242.0], [26.3, 290.0], [26.5, 340.0], [29.0, 363.0], [29.0, 430.0], [29.7, 450.0], [29.7, 500.0], .....

- 49개의 데이터를 가지고 있는 2차원 배열 fish_data가 생성됨

 

# label 생성

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

**    = 도미데이터        = 빙어 데이터  **


# knn(k-최근점이웃) 알고리즘 불러오기

from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()

- 생성된 모델이 변수 kn. 앞으로 이 변수를 이용해 학습

 

# 위에서 만들어준 입력데이터와 정답데이터를 입력으로 학습 진행

kn.fit(fish_data, fish_target)

 

# score : 학습된 모델을 평가

- ret 정확도[0,1]

kn.score(fish_data, fish_target)
# 결과값이 1 => 모두 맞혔다

 

# 입력 데이터에 대해 class를 추정

# predecit 2차원 배열을 입력으로
# 주변의 데이터들과의 거리를 근거로 입력데이터를 예측
kn.predict([[30, 600]])   # [1] 도미
kn.predict([fish_data[-1]])   # [0] 빙어

 

# 학습에 쓰인 입력데이터 출력라벨 쉽게 가져오기

kn._fit_X # 입력 데이터

kn._y # 정답 데이터

입력 데이터 :

array([[ 25.4, 242. ], [ 26.3, 290. ], [ 26.5, 340. ], [ 29. , 363. ], [ 29. , 430. ], [ 29.7, 450. ], [ 29.7, 500. ], ......

 

정답데이터:

array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

 

# k 변경하기

- 예측하고자 하는 데이터의 주변 몇 개의 데이터를 볼 것인지 정할 수 있음 (k의 역할)

# 옵션값을 주고 새로운 모델 생성
kn49 = KNeighborsClassifier(n_neighbors=49)

 


K-최근접 이웃 알고리즘

- 지도학습

- 비지도학습인 클러스터링과 유사한 방식

- 데이터들 간의 거리를 참고해 분류작업

- '유클리디안 거리' 계산법 적용

- k의 수만큼의 주변 데이터를 관찰하기 때문에 홀수여야 한다

 

# knn 적용 시 주의사항

- 학습 전 입력데이터들을 정규화시키자

이 때, 대표적인두가지 변수 재조정 방법이 있다.

최소-최대 정규화 z-점수 표준화 (
변수의 범위를 0% ~ 100%로 조정

변수의 범위를 평균에서 떨어져 있는 정도를 이용해 확대 혹은 축소



- 최소값과 최대값이 [0,100] 범위에 없을 수도 있음
- 수의 범위를 정확히 파악한 후에 사용하기
- 수의 범위 정확하게 파악하지 않아도 됨

 

# knn 장/단점

- 수치 데이터 해석단계에서 시간을 많이 투자해야 한다.

출처:https://m.blog.naver.com/bestinall/221760380344

- 데이터가 많아지면 유클리디안 거리 연산하는 시간도 비례적으로 늘어나기에 분류 속도가 느리다

 


 

# 훈련 세트 테스트 세트 분리의 필요성

  • 알고리즘의 성능을 제대로 평가하려면 훈련 데이터와 평가에 사용할 데이터는 각각 달라야 한다.

     ∵ 훈련에 사용되는 데이터로 평가한다면 답지를 들고 시험을 치르는 것과 같기 때문!

  • 평가에 사용되는 데이터 - 테스트 세트 , 훈련에 사용되는 데이터 - 훈련 세트
  • 훈련 전에 미리 데이터를 분리하자

# 3강과 동일하게 fish_data, fisht_target를 만든다

fish_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, 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]
fish_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, 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]
fish_data = [[l, w] for l, w in zip(fish_length, fish_weight)]
fish_target = [1]*35 + [0]*14
from sklearn.neighbors import KNeighborsClassifier

kn = KNeighborsClassifier()

 

# 도미와 빙어 데이터가 골고루 섞인 데이터를 학습해야 한다.

   -> 학습하지 않은 데이터에 대해 분류 성능이 올라간다.

 

# 훈련데이터를 넘파이 배열로 변환

import numpy as np

input_arr = np.array(fish_data)
target_arr = np.array(fish_target)

- input_arr (49, 2) 2차원 배열

- target_arr (49, ) 1차원 배열

 

# np.random.seed(x)

- 랜덤 시드를 설정하면 매번 동일하게 섞인 값을 사용할 수 있다.

np.random.seed(42)

 

# 섞인 값은 섞인 index배열을 사용

index = np.arange(49) # 0~48까지 1씩 증가하는 배열
print(index)
np.random.shuffle(index)
print(index)

 

섞이기 전 index 형태 :

[ 0 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48]

 

섞인 index 형태 :

[13 45 47 44 17 27 26 25 31 19 12 4 34 8 3 6 40 41 46 15 9 16 24 33 30 0 43 32 5 29 11 36 1 21 2 37 35 23 39 10 22 18 48 20 7 42 14 28 38]

 

# 슬라이싱을 이용해 데이터 분리

# train : [0] ~ [34]
train_input = input_arr[index[:35]]
train_target = target_arr[index[:35]]

# test : [35] ~ [48]
test_input = input_arr[index[35:]]
test_target = target_arr[index[35:]]

 

# 잘 섞였는지 그래프를 통해 확인

import matplotlib.pyplot as plt

# [:, 0]길이, [;, 1]무게
plt.scatter(train_input[:, 0], train_input[:, 1])
plt.scatter(test_input[:, 0], test_input[:, 1])
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

# 훈련과 검증

kn = kn.fit(train_input, train_target)

kn.score(test_input, test_target) # 정확도 1.0

kn.predict(test_input)
# test_target : array([0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0])
# 결과        : array([0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0])

# 지도학습

- 훈련하기 위한 입력데이터와 정답(타깃데이터)이 필요

 

# 비지도학습

- 입력데이터만 필요

- 정답이 없으므로 입력데이터를 가지고 특징을 찾아야 함

 

+) 강화학습

- 알고리즘이 행동한 결과로 얻은 보상으로 학습 

 


데이터전처리 / 표준점수 / 데이터세트 나누기

데이터 준비!

import numpy as np

fish_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, 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]
fish_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, 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]
                
fish_data = np.column_stack((fish_length, fish_weight))

fish_target = np.concatenate((np.ones(35), np.zeros(14)))

fish_data [:5] :

[[ 25.4 242. ] [ 26.3 290. ] [ 26.5 340. ] [ 29. 363. ] [ 29. 430. ]] ...

 

fish_target :

[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

 

# 훈련세트와 테스트세트 나눠주는 라이브러리 불러오기

from sklearn.model_selection import train_test_split

 

# 데이터 세트 나눠주기

train_input, test_input, train_target, test_target = train_test_split(
    fish_data, fish_target, stratify=fish_target, random_state=42)

- startify : 타겟데이터를 보고 데이터가 적다고 판단되면 비율을 적절히 조절한다

# 기준을 맞춰라 = 데이터 전처리 작업

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')
plt.xlim((0, 1000))
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

- 길이데이터들은 무게 데이터들에 비해 크기가 매우 작아서 그래프에서도 한쪽으로 쏠린 듯 출력되었다.

따라서 무게와 길이 기준을 맞춰주어야 한다.

 

mean = np.mean(train_input, axis=0)  # 평균
std = np.std(train_input, axis=0)    # 표준편차

- 평균과 표준편차를 구해준다.

- axis = 0으로 설정했으니 행을 따라 열의 통계값을 계산한다.

mean : [ 27.29722222 454.09722222]

std    : [ 9.98244253 323.29893931]

 

# 표준점수

- 데이터 전처리 작업 중 하나. 

- 각 특성값이 0에서 표준편차의 몇 배만큼 떨어져 있는지 나타냄

- (특성 - 평균mean) / 표준편차std

- z점수

# 넘파이 브로드캐스팅 적용
# 모든셀에서 mean이 알아서 빼짐
train_scaled = (train_input - mean) / std
test_scaled = (test_input - mean) / std

표준점수 구하는 과정

 

# 주의할점!

- 새로운 데이터를 그래프로 출력할때 표준점수로 변환하는 것 잊지 않기

- 훈련세트를 변환한 방식 그대로 테스트세트도 변환해야 한다

plt.scatter(train_scaled[:,0], train_scaled[:,1])
# plt.scatter(25, 150, marker='^')
new = ([25, 150] - mean) / std
plt.scatter(new[0], new[1], marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

 

# 학습

- 학습결과 정확도 100%인 모습

kn.fit(train_scaled, train_target)
kn.score(test_scaled, test_target) # 1.0

 

'ESL 연구실 활동 > LAB' 카테고리의 다른 글

mediapipe를 이용한 3D shoe detection  (0) 2022.02.24
혼공머 회귀 작성중  (0) 2022.01.30
오늘 한 거  (0) 2022.01.26
컴구 운체 강의 추천  (0) 2022.01.23
Pythorch 입문 - 다중회긔  (0) 2022.01.20
Pytorch 입문 - 선형회귀  (0) 2022.01.20