핀아의 저장소 ( •̀ ω •́ )✧
[ML] 혼자 공부하는 머신러닝_2장 본문
💡 학습 목표
1. 지도 학습과 비지도 학습의 차이점 비교
2. 훈련 세트와 테스트 세트의 정의
3, 샘플링 편항 및 해결 방안
4. 데이터 전처리의 필요성
목차
- 지도 학습 vs 비지도 학습
- 훈련 세트와 테스트 세트
- 샘플링 편향
- 샘플링 편향 문제 해결하기
- 데이터 전처리
1️⃣ 지도 학습 vs 비지도 학습
머신러닝 알고리즘은 크게 지도 학습과 비지도 학습으로 나눌 수 있음
✅ 지도 학습 (supervised learning)
- 지도 학습 알고리즘은 훈련 데이터(training data)가 필수로 필요함.
- 일반적으로 지도 학습에서 데이터는 입력(input), 정답은 타깃(target)이라 표현하며 이 둘을 합쳐 훈련 데이터(training data)라 부름
- 지도 학습은 정답이 있으니 알고리즘이 정답을 맞히는 것을 학습하여 새로운 데이터를 예측하는데 활용함
- 1장에서 사용한 K-최근접 이웃 알고리즘도 지도 학습 알고리즘 중 하나임
✅ 비지도 학습 (unsupervised learning)
- 타깃 없이 입력 데이터만 있을 때 사용함
- 타깃을 사용하지 않으므로 정답을 맞힐 수 없으나 데이터를 파악하거나 변형하는 데 도움을을 주는데 활용함
2️⃣ 훈련 세트와 테스트 세트
💡 훈련 세트와 테스트 세트의 개념에 대해 알아보고 1장에서 사용된 도미와 빙어 데이터를 훈련 세트와 테스트 세트로 나눠 모델 학습을 수행 해봄
- 머신러닝 알고리즘의 성능을 제대로 평가하려면 훈련 데이터와 평가에 사용할 데이터가 달라야함
- 일반적으로 이미 준비된 데이터 중에서 일부를 떼어 내어 활용하는 경우가 많음
- 평가에 사용하는 데이터를 테스트 세트(test set), 훈련에 사용되는 데이터를 훈련 세트(train set)라 부름
- 일반적으로 훈련 세트의 양은 클 수록 좋으며 테스트 세트를 제외한 모든 데이터를 사용함
- 테스트 세트는 전체 데이터의 20% ~ 30%의 비율로 사용되며 전체 데이터가 아주 크다면 1%만 덜어내도 충분할 수 있음
✅ 생선 데이터 셋 분리
# 도미 데이터
# 빙어 데이터
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
#훈련 데이터
train_input = fish_data[:35]
train_target = fish_target[:35]
#테스트 데이터
test_input = fish_data[35:]
test_target = fish_target[35:]
✅ K-최근접 이웃 알고리즘 정의 및 훈련
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
kn = kn.fit(train_input, train_target)
kn.score(test_input, test_target)
'''
결과 : 0.0
'''
plt.scatter([tmp[0] for tmp in train_input], [tmp[1] for tmp in train_input], label="train set")
plt.scatter([tmp[0] for tmp in test_input], [tmp[1] for tmp in test_input], label="test set")
plt.xlabel('length')
plt.ylabel('weight')
plt.legend()
plt.show()
3️⃣ 샘플링 편향
💡 2절의 K-최근접 이웃 알고리즘 정의 및 훈련의 결과 모델 정확도가 0.0(0%)임을 확인 할 수 있음
1장에서 동일한 데이터로 모델을 학습시킨 K-최근접 이웃 알고리즘의 모델 정확도는 1.0(100%)이 나온것과 비교하여 차이점이 무엇인지 확인해봄
- 샘플링 편향이란 훈련 세트와 테스트 세트에 샘플이 고르게 섞여 있지 않을때 나타나는 현상임
- 위 예의 생선 데이터의 훈련 세트를 보면 도미만 존재하기 때문에 테스트 세트가 무엇이든 무조건 도미로 판단함
- 반면 테스트 세트는 빙어만 존재하기 때문에 모델의 정확도는 0.0으로 측정됨
✅ 샘플링 편향 문제 해결하기
- 훈련 세트와 테스트 세트를 나누기 전에 데이터를 잘 섞거나 골고루 샘플을 뽑아서 훈련 세트와 테스트 세트를 만들어야함
- 이 작업을 간편하게 처리할 수 있도록 도와주는 넘파이(numpy) 라이브러리가 존재함
🔸 샘플링 편향 문제를 해결 하여 데이터 셋 분리
import numpy as np
#list to array
input_arr = np.array(fish_data)
target_arr = np.array(fish_target)
print(input_arr)
'''
[[ 25.4 242. ]
[ 26.3 290. ]
[ 26.5 340. ]
[ 29. 363. ]
[ 29. 430. ]
...
]
'''
print(input_arr.shape)
#(49, 2)
#랜덤 셔플링을 하기위한 index 생성
np.random.seed(42)
index = np.arange(49)
np.random.shuffle(index)
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
]
'''
#훈련 세트와 테스트 세트 분리
train_input = input_arr[index[:35]]
train_target = target_arr[index[:35]]
test_input = input_arr[index[35:]]
test_target = target_arr[index[35:]
import matplotlib.pyplot as plt
plt.scatter(test_input[:, 0], test_input[:, 1], label="test set")
plt.xlabel('length')
plt.ylabel('weight')
plt.legend()
plt.show()
🔸 K-최근접 이웃 알고리즘 정의 및 훈련
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
kn = kn.fit(train_input, train_target)
kn.score(test_input, test_target)
'''
결과 : 1.0
'''
🔸 테스트 데이터 분류 예측
#테스트 데이터 예측 하기
kn.predict(test_input)
#array([0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0])
#실제 테스트 예측 값과 비교
print(test_target)
#array([0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0])
4️⃣ 데이터 전처리
💡 머신러닝 모델에 훈련 데이터를 주입하기 전 가공하는 단계로 특성값을 일정한 기준으로 맞추어 주는 작업임
전처리 데이터로 훈련했을 때의 차이를 알아보고 사용된 스케일 변환 방법을 배움
✅ 넘파이로 데이터 준비하기
💡 넘파이를 사용하기에 조금 더 세련된 방법으로 도미와 빙어 데이터를 합침
# 도미 데이터
# 빙어 데이터
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
]
import numpy as np
fish_data = np.column_stack((fish_length, fish_weight))
fish_target = np.concatenate((np.ones(35), np.zeros(14)))
print(fish_data[:5])
'''
[[ 25.4 242. ]
[ 26.3 290. ]
[ 26.5 340. ]
[ 29. 363. ]
[ 29. 430. ]]
'''
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.]
'''
✅ 사이킷런으로 훈련 세트와 테스트 세트 나누기
💡 앞서 인덱스를 생성하여 번거로운 방법을 통해 데이터 셋을 분류함
사이킷런을 사용하여 세련된 방법으로 훈련 세트와 테스트 세트를 나눠봄
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)
'''
param
1) test_size
- 테스트 데이터 세트의 비율(default = 0.25)
2) stratify
- 데이터 평향이 발생하지 않도록 target 비율에 맞게 데이터들이 랜덤하게 섞임
'''
print(train_input.shape, test_target.shape)
#(36, 2) (13,)
#데이터가 잘 섞였는지 확인
print(test_target)
#[0. 0. 1. 0. 1. 0. 1. 1. 1. 1. 1. 1. 1.]
✅ K-최근접 이웃 알고리즘 생성 및 훈련
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
kn.fit(train_input, train_target)
kn.score(test_input, test_target)
'''
결과 : 1.0
'''
✅ 수상한 생선 데이터 분류 예측
길이가 25cm, 무게가 150g인 생선의 종류를 예측해보자
import matplotlib.pyplot as plt
plt.scatter(train_input[:, 0], train_input[:, 1], label='train set')
plt.scatter(25, 150, marker='^', label='new fish')
plt.xlabel('length')
plt.ylabel('weight')
plt.legend()
plt.show()
new_fish = [[25, 150]]
print(kn.predict(new_fish))
#[0.], 빙어로 예측
⚠️실제 25cm, 150g인 생선은 도미며 예측 값이 틀림을 알 수 있음
✅ 수상한 생선 데이터에서 가까운 샘플 확인하기
💡 KNeighborsClassifier 클래스는 주어진 샘플에서 가장 가까운 이웃을 찾아주는 kneighbors() 메서드를 제공함 KNeighborsClassifier 클래스의 이웃 개수인 n_neighbors의 기본 값은 5이므로 5개의 이웃이 반환됨
new_fish = [[25, 150]]
distances, indexes = kn.kneighbors(new_fish)
print(distances)
# array([[ 92.00086956, 130.48375378, 130.73859415, 138.32150953, 138.39320793]])
print(indexes)
# array([[21, 33, 19, 30, 1]])
import matplotlib.pyplot as plt
plt.scatter(train_input[:, 0], train_input[:, 1], label='test set')
plt.scatter(25, 150, marker='^', label='new fish')
plt.scatter(train_input[indexes, 0], train_input[indexes, 1], marker='D', label='neighbors sample')
plt.xlabel('length')
plt.ylabel('weight')
plt.legend()
plt.show()
⚠️새로운 생선 데이터의 이웃에는 도미보다 빙어가 더 많이 분포 되어있음을 알 수 있음
✅ 스케일 변환
💡 사람이 데이터의 산점도를 봤을때 새로운 생선의 이웃 샘플은 빙어보다 도미가 더 많아 보임에도 실제 거리를 측정한 결과 빙어가 훨씬 많았음
이 이유에 대해 알아보고 스케일 변환 과정을 통해 올바르게 예측 할 수 있도록 조정해봄
- x축, y축 기준 맞추기
x축(length)과 y축(weight)의 범위 차가 너무 크기 때문에 y축으로 조금만 멀어져도 거리가 아주 큰 값으로 계산되는 문제가 발생함
xlim() 메서드를 통해 x축과 y축의 범위를 동일하게 맞춰 데이터의 산점도를 확인함
import matplotlib.pyplot as plt
plt.scatter(train_input[:,0], train_input[:,1], label='train set')
plt.scatter(25, 150, marker='^', label='new fish')
plt.scatter(train_input[indexes,0], train_input[indexes,1], marker='D', label='neighbors sample')
plt.xlim((0, 1000))
plt.xlabel('length')
plt.ylabel('weight')
plt.legend()
plt.show()
x축과 y축의 범위를 동일하게 맞춘 결과 모든 데이터가 수직으로 늘어선 형태가 되었음
생선의 길이(x축)는 가장 가까운 이웃을 찾는데 큰 영향을 미치지 않았고 생선의 무게(y축)만 고려 대상이 됨
- 생선의 길이와 무게의 값이 놓인 범위가 매우 다르기 때문에 두 특성의 스케일을 조정해야함
- K-최근접 이웃과 같은 거리 기반 알고리즘일 경우 더더욱 데이터 전처리 과정을 통해 스케일 변환을 수행해야함
◾ 훈련 데이터 스케일 변환 하기
가장 널리 사용되는 전처리 방법 중 하나는 표준점수(standard score)를 사용하여 스케일을 변환함
Z = (특성-평균)/표준편차
#평균
mean = np.mean(train_input, axis = 0)
#표준편차
std = np.std(train_input, axis = 0)
'''
axis = 0, 행을 따라 각 열의 값을 계산함
'''
print(mean, std)
#[ 27.29722222 454.09722222] [ 9.98244253 323.29893931]
#표준점수
train_scaled = (train_input - mean) / std
#넘파이의 브로드캐스팅 기능을 이용하여 계산
⚠️ 브로드캐스팅
크기가 다른 넘파이 배열에서 자동으로 사칙 연산을 모든 행이나 열로 확장하여 수행하는 기능
✅ 전처리 데이터(스케일 변환 데이터)로 모델 훈련 및 수상한 생선 데이터 분류 예측
💡 표준점수로 변환한 train_scaled를 사용하여 모델을 학습하기 전에 테스트 데이터 및 새롭게 예측할 데이터도 표준점수로 변환하는 과정이 필요함
그 이유는 훈련 세트를 스케일 변환 하게 되면 특성(length, weight)의 값이 변하게됨
그에 맞춰 테스트 데이터 및 수상한 생선 데이터 또한 스케일 변환 해줄 필요가 있음
주의 사항은 훈련 데이터 스케일 변환에 사용된 평균과 표준편차 값을 사용하여 동일한 수치로 테스트 데이터 및 새롭게 예측할 데이터의 스케일 변환을 수행해야함
#수상한 생선 데이터를 스케일 변환 하지 않으면 나타나는 문제점 확인
import matplotlib.pyplot as plt
#표준점수 변환 전 new fish 데이터 확인
plt.scatter(train_scaled[:,0], train_scaled[:,1], label='train set')
plt.scatter(25, 150, marker='^', label='new fish')
plt.xlabel('length')
plt.ylabel('weight')
plt.legend()
plt.show()
- 모델 학습 후 표준점수 스케일 변환된 테스트 데이터를 기반으로 모델 정확도 측정
#모델 학습
kn.fit(train_scaled, train_target)
#테스트 데이터 표준점수 스케일 변환
test_scaled = (test_input - mean) / std
#모델 정확도 측정
kn.score(test_scaled, test_target)
'''
결과: 1.0
'''
- new fish 예측 후 산점도를 통해 이웃 샘플 확인
#수상한 생선 데이터 스케일 변환
new = ([25, 150] - mean) / std
print(kn.predict([new]))
#[1.0], 도미로 예측
import matplotlib.pyplot as plt
distances, indexes = kn.kneighbors([new])
plt.scatter(train_scaled[:, 0], train_scaled[:, 1], label='train_scaled')
plt.scatter(new[0], new[1], marker='^')
plt.scatter(train_scaled[indexes, 0], train_scaled[indexes, 1], marker='D', label='neighbors sample')
plt.xlabel('length')
plt.ylabel('weight')
plt.legend()
plt.show()
'Big Data > ML & DL' 카테고리의 다른 글
[ML] 혼자 공부하는 머신러닝_5장 (0) | 2023.06.01 |
---|---|
[ML] 혼자 공부하는 머신러닝_4장 (0) | 2023.05.30 |
[ML] 혼자 공부하는 머신러닝_3장-2 (0) | 2023.05.23 |
[ML] 혼자 공부하는 머신러닝_3장-1 (1) | 2023.05.22 |
[ML] 혼자 공부하는 머신러닝_1장 (0) | 2023.05.16 |
Comments