본문 바로가기

머신러닝 & 딥러닝

[머신러닝/딥러닝] PART 2

<학습목표>-------------------------------------------

-머신러닝 알고리즘에 주입할 데이터를 준비하는 방법을 배운다.

-데이터의 형태가 알고리즘에 미치는 영향을 이해

 

 

<지도 학습, 비지도 학습, 강화학습>-------------------------------------------

지도학습(supervised learning): 훈련을 위한 데이터(input)와 정답(target)이 있어야 한다.(문제집 & 정답지)

input 과 target을 합쳐서 훈련 데이터(Traning data)라고 한다.

특성(피쳐, feature): 입력으로 사용된 길이와 무게를 의미, 특성들을 합치면 입력(input)이 된다.

 

비지도학습(supervised learning)

입력 데이터만 활용한다. 답을 맞추는게 아닌 데이터의 규칙을 파악하는데 유용

 

강화학습(reinforcement learning)

맞는길 가면  +1, 틀린길 가면 -1 하면서 보상을 주면서 가중치가 증가하는 방향으로 학습된다.

 

 

<훈련 세트와 테스트 세트>-------------------------------------------

Train set: 훈련에 사용하는 데이터

 

Test set: 평가에 사용하는 데이터(훈련 데이터의 일부를 떼어내 테스트 세트로 사용, 보통 7:3비율로 학습셋 테스트셋 나눔)

 

sample: 하나의 데이터를 의미,  [생선길이, 생선무게]가 샘플이다. 1장의 생선데이터는 총 49개의 샘플의 집합과 마찬가지 이다.

 

 

<샘플링 편향 (sampling bias) 문제>-------------------------------------------

지도학습의 개념을 알았으니, 1장의 코드를 조금 수정해보겠습니다. 35개의 도미 샘플을 학습셋, 14개의 빙어 샘플을 테스트셋으로 설정해보겠습니다.

# 도미의 길이, 무게 리스트 35개
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]

# 빙어의 길이와 무게 리스트 14개
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]


import matplotlib.pyplot as plt    # 그래프 그림을 그릴때 쓰는 라이브러리 호출(맷플롯립 )
from sklearn.neighbors import KNeighborsClassifier     # K-최근접 이웃 분류 알고리즘 호출(사이킷런 머신러닝 패키지)

All_fish_length=bream_length + smelt_length
All_fish_weight=bream_weight + smelt_weight
All_fish_answer = [1]*35+[0]*14    # Superviser 학습을 위한 정답지 만들기 (1이면 도미, 0이면 빙어이다.)
All_data = [[a,b] for a,b in zip(All_fish_length, All_fish_weight)]    # 사이킷런 활용을 위한 2차원 리스트 쌍 [[길이,무게], [길이,무게]...]

kn = KNeighborsClassifier()    # K-최근접 이웃분류 클래스 인스턴스화 하기 (n_neighbors=15를 클래스 괄호 안에 넣어주면 이웃체크수 15개로 변경 가능)
kn.fit(All_data[:35], All_fish_answer[:35])    # 학습셋 35개 
kn.score(All_data[36:], All_fish_answer[36:])    # 테스트셋 14개 설정

이때 Accuracy가 0.0이 나와버렸습니다.

그 이유는 35개의 학습셋이 전부 도미로 채웠는데, 당연히 14개의 빙어셋을 테스트로 사용하니

마치 공부한 시험범위에서 문제가 안나오고 전부 다른 Part에서만 문제가 출제된것과 마찬가지 입니다.

 

이렇게 훈련세트와 테스트셋이 골고루 섞이지 않아서 발생하는 문제를 샘플링 편향(Sample bias)문제 라고 합니다.

numpy 라이브러리를 사용하면 이런 데이터 혼합문제를 해결할수 있습니다.

 

 

<넘파이(numpy)>-------------------------------------------

파이썬의 대표적인 계산&배열 라이브러리, 앞전에 파이썬 리스트로 2차원 배열을 표현하기가 매우 번거로웠다.

이때 넘파이 라이브러리는 고차원 배열을 손쉽게 만들고 조작할 수 있는 간편한 도구를 제공한다.

 

이제 생선 데이터를 넘파이 배열로 가공해보겠습니다.

import numpy as np
input_arr = np.array(All_data)     # 파이썬 리스트를 넘파이로 변환
target_arr = np.array(All_fish_answer)    # 파이썬 리스트를 넘파이로 변환

print(input_arr.shape)    # 샘플개수, 특성개수 출력

이제 샘플링 편향을 방지하기 위해 학습 데이터를 섞어주기만 하면 됩니다. 이때 target_arr에 담긴 정답 까지 순서가 뒤바뀌어 버리면 안됨으로, 샘플과 타깃이 한몸이 되어서 섞여야 한다는점을 주목해야 합니다.

 

0~48까지의 인덱스 번호자체를 섞은뒤, 나누면 됩니다. 그리고 이 번호를 기준으로 학습셋, 데이터셋을 나누면 됩니다.

np.random.seed(42)    #항상 동일한 결과를 출력하기 위해서 시드번호를 부여한다.(시드번호 있으면 항상 고정된 랜덤배열이 생성)
index = np.arange(49)    # 0부터 48까지의 정수가 담긴 배열을 생성한다.
np.random.shuffle(index)    #넘파이 배열을 섞는다.

print(index)

mlist =[0,1,2]
print(input_arr[mlist])    # 넘파이 배열은 이렇게 원하는 인덱스번호가 담긴 리스트를 넣으면 알아서 해당 인덱스 번호만 뽑아준다.

# 학습셋 만들기    (49개중 35개를 학습셋으로 사용)
train_input = input_arr[index[:35]]
train_target = target_arr[index[:35]]

# 테스트셋 만들기    (49개중 14개를 테스트셋으로 사용)
test_input = input_arr[index[35:]]
test_target = target_arr[index[35:]]

print()

랜덤 셔플 결과와, 0,1,2인덱스 번호에 위치한 numpy 배열도 잘 보인다

이제 산도표 그래프를 활용해서 학습셋과 테스트셋을 구분해보도록 하겠습니다.

import matplotlib.pyplot as plt
plt.scatter(train_input[:, 0], train_input[:,1], label='train')     # 모든 행의 0번째 열(길이), 1번째 열(무게)를 가져온다는 말이다. 다차원 넘파이 배열만의 접근법인가 보다
plt.scatter(test_input[:, 0], test_input[:,1], label='test')
plt.xlabel('length')
plt.ylabel('weight')
plt.legend()    # 범례 출력하기
plt.show()

파랑: 학습샘플, 주황: 테스트샘플

이제 학습셋을 바탕으로 훈련을 진행, 테스트셋을 바탕으로 시험을 보도록 하겠습니다.

kn.fit(train_input, train_target)    # 학습셋 바탕으로 학습 진행하기
kn.score(test_input, test_target)    # 테스트셋 바탕으로 학습 진행하기(1.0의 정확도!)

# 직접 쿼리문 날려서 결과 확인하기(둘다 정확하게 일치한다.)
print(kn.predict(test_input))
print(test_target)

100% 다 맞추었습니다.

이렇게 완성하였습니다 아래는 전체 코드 입니다.