본문 바로가기
Python/ML

[머신러닝] 샘플링 편향, 넘파이(생선 분류 문제2)

by JooRi 2023. 1. 15.
728x90
SMALL
* 교재: 혼자 공부하는 머신러닝+딥러닝 (hanbit.co.kr)

 

* 문제: 넘파이를 사용하여 샘플링 편향을 해결한다.

샘플링 편향을 경험해 보고 이를 해결하기 위해 넘파이를 사용하여 도미와 빙어를 구분하는 머신러닝 프로그램을 만든다.

 

* 문제 해결 과정

1. 생선 데이터 준비하기

2. 2차원 리스트 만들기  

3. KNeighborsClassifier 클래스를 임포트 한 후 객체 만들기

4. 훈련 세트와 테스트 세트 만들기

5. 훈련 세트로 모델 훈련하기

6. 테스트 세트로 모델의 성능 평가하기 → 샘플링 편향

7. 생선 데이터를 2차원 넘파이 배열로 변환하기

  1) 넘파이 라이브러리 임포트 하기

  2) 넘파이 array() 함수에 파이썬 리스트 전달하기

8. 랜덤하게 샘플을 선택해 훈련 세트와 테스트 세트 만들기

  1) 인덱스 만들기

  2) 랜덤하게 훈련세트 만들기

  3) 랜덤하게 테스트 세트 만들기

9. 모델 훈련하기, 모델의 성능 평가하기

 

 

1. 생선 데이터 준비하기

도미 35마리와 빙어 14마리를 합친 총 49마리의 생선의 길이와 무게 리스트를 준비해 보자.

 

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]

 

하나의 생선 데이터를 샘플이라고 부른다.

도미 35마리, 빙어 14마리가 있으므로 전체 생선 데이터는 총 49개의 샘플이 있다.

 

 

2.  2차원 리스트 만들기

대표적인 머신러닝 라이브러리인 사이킷런을 사용하려면 2차원 리스트를 만들어야 한다.

length와 weight 리스트를 2차원 리스트로 만들어보자.

 

fish_data = [[l, w] for l, w in zip(fish_length, fish_weight)]
print(fish_data)

# 출력: [[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], [30.0, 390.0], [30.0, 450.0], [30.7, 500.0], [31.0, 475.0], [31.0, 500.0], [31.5, 500.0], [32.0, 340.0], [32.0, 600.0], [32.0, 600.0], [33.0, 700.0], [33.0, 700.0], [33.5, 610.0], [33.5, 650.0], [34.0, 575.0], [34.0, 685.0], [34.5, 620.0], [35.0, 680.0], [35.0, 700.0], [35.0, 725.0], [35.0, 720.0], [36.0, 714.0], [36.0, 850.0], [37.0, 1000.0], [38.5, 920.0], [38.5, 955.0], [39.5, 925.0], [41.0, 975.0], [41.0, 950.0], [9.8, 6.7], [10.5, 7.5], [10.6, 7.0], [11.0, 9.7], [11.2, 9.8], [11.3, 8.7], [11.8, 10.0], [11.8, 9.9], [12.0, 9.8], [12.2, 12.2], [12.4, 13.4], [13.0, 12.2], [14.3, 19.7], [15.0, 19.9]]

 

zip() 함수는 나열된 리스트에서 원소를 하나씩 꺼내주는 일을 한다.

for문은 zip() 함수로 length와 weight 리스트에서 원소를 하나씩 꺼내어 l과 w에 할당한다. 그러면 [l, w]가 하나의 원소로 구성된 리스트가 만들어진다.

첫 번째 생선의 길이 25.4cm와 무게 242.0g이 하나의 리스트를 구성하고 이런 리스트가 모여 전체 리스트가 만들어졌다.

 

 

컴퓨터가 문자를 이해할 수 있게 도미와 빙어를 숫자 1과 0으로 표현해 보자.

 

fish_target = [1]*35 + [0]*14
print(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]

 

도미를 1로 놓고 빙어를 0으로 놓았다.

첫 번째 생선은 도미이므로 1이고 마지막 생선은 빙어이므로 0이 된다. 즉 정답 리스트는 1이 35번 등장하고 0이 14번 등장한다.

 

 

3. KNeighborsClassifier 클래스를 임포트 한 후 객체 만들기

사이킷런 k-최근접 이웃 분류 모델을 만드는 클래스인 KNeighborsClassifier를 임포트 한 후 KNeighborsClassifier 클래스의 객체를 만들어보자.

 

from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()

 

파이썬에서 from ~ import 구문은 모듈 전체를 임포트 하지 않고 특정 클래스만 임포트 하기 위해 사용한다.

KNeighborsClassifier 클래스의 객체 이름은 kn으로 저장하였고 클래스의 이름 뒤에 괄호를 붙여 클래스의 객체를 만들었다.

 

 

4. 훈련 세트와 테스트 세트 만들기

훈련 세트는 모델을 훈련할 때 사용하는 데이터이고, 테스트 세트는 모델을 평가할 때 사용하는 데이터이다.

전체 데이터의 처음 35개를 훈련 세트로, 나머지 14개를 테스트 세트로 사용해 보자.

 

train_input = fish_data[:35]  # 훈련 세트로 입력값중 인덱스 0부터 34까지 사용
train_target = fish_target[:35] # 훈련 세트로 타깃값 중 인덱스 0부터 34까지 사용
test_input = fish_data[35:]  # 테스트 세트로 입력값 중 인덱스 35부터 끝까지 사용
test_target = fish_target[35:]  # 테스트 세트로 타깃값 중 인덱스 35부터 끝까지 사용

 

슬라이싱 연산으로 인덱스 0부터 34까지 처음 35개의 샘플을 훈련 세트로 선택하였다.

인덱스 35부터 끝까지 나머지 14개의 샘플을 테스트 세트로 선택하였다.

 

 

5. 훈련 세트로 모델 훈련하기

 

kn = kn.fit(train_input, train_target)

 

fit()을 호출해 모델을 훈련하였다.

fit()은 train_input과 train_target 이 2개의 훈련 데이터를 가지고 모델을 훈련한다.

 

 

6. 테스트 세트로 모델의 성능 평가하기

 

kn.score(test_input, test_target)  # 출력: 0.0

 

score()를 호출해 모델의 성능을 평가했더니 정확도가 0.0이 나왔다... 이유는 바로 '샘플링 편향'이다.

샘플링 편향이란 훈련 세트와 테스트 세트에 샘플이 골고루 섞여 있지 않아 샘플링이 한쪽으로 치우쳐지는 것을 의미한다.

상식적으로 훈련하는 데이터와 테스트하는 데이터에는 도미와 빙어가 골고루 섞여 있어야 하는데 훈련 세트에는 도미만 있고 빙어는 하나도 들어있지 않기 때문이다.

이를 해결하기 위해 넘파이를 사용해 보자.

 

 

7. 생선 데이터를 2차원 넘파이 배열로 변환하기 

넘파이는 파이썬의 대표적인 배열 라이브러리로 고차원의 배열을 손쉽게 만들 수 있다.

 

 

1) 넘파이 라이브러리 임포트 하기

 

import numpy as np

 

 

2) 넘파이 array() 함수에 파이썬 리스트 전달하기

 

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

 

[[25.4, 242.0]

 [26.3, 290.0]

...

 [15.0, 19.9]]

 

input_arr 배열을 출력하면 위와 같은 형태의 49개의 행과 2개의 열이 출력된다.

넘파이는 행과 열을 가지런히 출력한다.

 

 

8. 랜덤하게 샘플을 선택해 훈련 세트와 테스트 세트 만들기

샘플링 편향을 해결하기 위해 배열에서 랜덤하게 샘플을 선택해 훈련 세트와 테스트 세트로 만들어보자.

 

 

1) 인덱스 만들기

 

np.random.seed(42)
index = np.arange(49)
np.random.shuffle(index)

 

넘파이에서 무작위 결과를 만드는 함수들은 실행할 때마다 다른 결과를 만든다. 일정한 결과를 얻으려면 랜덤 시드(random seed)를 지정하면 된다.

넘파이 arange() 함수에 정수 n을 전달하면 0부터 n-1까지 1씩 증가하는 배열을 만든다.

넘파이 random 패키지 아래에 있는 shuffle() 함수는 주어진 배열을 무작위로 섞는다.

 

 

만들어진 인데스를 출력해 보자.

 

print(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]

0부터 48까지의 인덱스가 만들어졌고 랜덤하게 섞여서 출력되었다.

 

 

2) 랜덤하게 훈련 세트 만들기

이제 랜덤하게 섞인 인덱스를 사용해  전체 데이터를 훈련 세트와 테스트 세트로 나누어야 한다.

먼저 랜덤하게 처음 35개의 샘플을 훈련 세트로 만들어보자.

 

train_input = input_arr[index[:35]]
train_target = target_arr[index[:35]]

 

인덱스 배열의 처음 35개를 input_arr과 target_arr에 전달하여 랜덤하게 35개의 샘플을 훈련 세트로 만들었다. 

 

 

3) 랜덤하게 테스트 세트 만들기

랜덤하게 나머지 14개의 샘플을 테스트 세트로 만들어보자.

 

test_input = input_arr[index[35:]]
test_target = target_arr[index[35:]]

 

 

이제 모든 데이터의 준비가 끝났다.

훈련 세트와 테스트 세트에 도미와 빙어가 잘 섞여 있는지 산점도를 그려보자.

 

import matplotlib.pyplot as plt
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(test_input[:,0], test_input[:,1])
plt.xlable('length')
plt.ylable('weight')
plt.show()

 

 

파란색이 훈련 세트이고 주황색이 테스트 세트이다.

도미와 빙어가 잘 섞여서 산점도가 만들어졌다.

 

 

9. 모델 훈련하기, 모델의 성능 평가하기

이제 모델을 다시 훈련시켜 보자.

 

kn = kn.fit(train_input, train_target)
kn.score(test_input, test_target)  # 출력: 1.0

 

1.0이 출력되었으므로 100%의 정확도로 테스트 세트에 있는 모든 생선을 맞혔다!

 

 

* 용어 정리

1. 훈련 세트: 모델을 훈련할 때 사용하는 데이터

2. 테스트 세트: 모델을 평가할 때 사용하는 데이터

3. 샘플링 편향(sampling bias): 훈련 세트와 테스트 세트에 샘플이 골고루 섞여 있지 않아 샘플링이 한쪽으로 치우쳐지는 것

4. 넘파이(numpy): 파이썬의 대표적인 배열 라이브러리, 고차원의 배열을 손쉽게 만들고 조작할 수 있는 도구들을 제공

5. seed(): 넘파이에서 난수를 생성하기 위한 정수 초깃값을 지정, 랜덤 함수의 결과를 동일하게 하고 싶을 때 사용

6. arange(): 일정한 간격의 정수 또는 실수 배열을 만듦

7. shuffle(): 주어진 배열을 랜덤하게 섞음

8. 지도 학습: 머신러닝 알고리즘의 한 종류, 샘플의 입력과 타깃을 알고 있을 때 사용할 수 있는 학습 방법 

 

머신러닝 알고리즘은 크게 지도 학습과 비지도 학습으로 나눌 수 있다.

지도 학습은 훈련하기 위한 데이터와 정답이 필요하다.

지도학습에서 입력(데이터)과 타깃(정답)을 합쳐 훈련 데이터라고 한다.

k-최근접 이웃 알고리즘은 입력과 타깃을 사용하므로 지도 학습이다.

 

728x90
LIST

댓글