본문 바로가기
딥러닝 & 머신러닝/혼자 공부하는 머신러닝 딥러닝

2-2. 데이터 전처리

by sim0609 2023. 2. 7.

데이터 전처리

훈련 세트와 테스트 세트만 잘 분류했다고 모든 문제가 해결된게 아니다

클래스간의 특성값들의 스케일이 다르게 되면(특성값들간의 크기 차이가 크면) 안정적인 예측이 불가능하기 때문에 엉뚱한 예측을 할 가능성이 높아진다

 

→ 따라서, 표준 점수 변환을 통해 모든 데이터의 특성값들을 일정한 기준으로 맞춰줘야 한다

 

소스코드

import numpy as np
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

# 도미와 빙어를 합친 데이터 세트
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]
                
# 길이와 무게를 짝지어주는 방법2
fish_data = np.column_stack((fish_length, fish_weight))

# 데이터 labeling 해주기
fish_target = np.concatenate((np.ones(35), np.zeros(14)))

# 전달되는 리스트나 배열을 비율에 맞게 훈련 세트와 테스트 세트로 나누어줌
# 전체 데이터에서 1/4만 테스트 세트로 추출하는 train_test_split 함수 이용
train_input, test_input, train_target, test_target = train_test_split(fish_data, fish_target, random_state = 42)

# stratify에 타깃 데이터를 전달해 클래스 비율에 맞게 데이터를 나누기
train_input, test_input, train_target, test_target = train_test_split(fish_data, fish_target, stratify = fish_target, random_state = 42)

# 모델 학습시키기
kn = KNeighborsClassifier()
kn.fit(train_input, train_target)
kn.score(test_input, test_target)

# 새로운 데이터 분류
print(kn.predict([[25, 150]]))

# 새로운 데이터의 위치를 산점도를 통해 알아보기
plt.scatter(train_input[:, 0], train_input[:, 1])
plt.scatter(25, 150, marker = '^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

# kneighbors를 통해 새로운 데이터와 이웃까지의 거리, 이웃 샘플들의 인덱스 반환 
distances, indexes = kn.kneighbors([[25, 150]])
print(distances)
print(indexes)
# 5개의 이웃 데이터들의 정보
print(train_input[indexes])
print(train_target[indexes])

# 5개의 이웃 샘플들의 위치 산점도로 표현
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.xlabel('length')
plt.ylabel('weight')
plt.show()

# 거리상으로 새로운 데이터가 도미와 더 가까운데 빙어로 분류함
# -> y축의 크기 간격이 크기 때문에 y축으로 조금만 멀어져도 거리가 멀어짐
# x축의 거리를 y와 동일하게해 이웃 데이터의 위치를 살펴보자
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()

# 훈련 데이터의 평균과 표준편차를 통해 표준 점수를 구한 후 특성값(train_length, train_target)의 기준을 맞춰주자
mean = np.mean(train_input, axis = 0)
std = np.std(train_input, axis = 0)
train_scaled = (train_input - mean) / std

# 특성값을 일정한 기준으로 맞춰준 후 훈련 데이터를 산점도로 표현하기
plt.scatter(train_scaled[:,0], train_scaled[:, 1])
plt.scatter(25, 150, marker = '^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

# 새로운 데이터도 다른 샘플들과 동일한 비율로 변환
new_data = ([25, 150] - mean) / std
plt.scatter(train_scaled[:, 0], train_scaled[:, 1])
plt.scatter(new_data[0], new_data[1], marker = '^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

# 모델 학습하기
kn.fit(train_scaled, train_target)

# 테스트 세트도 표준 점수로 변환해주기
test_mean = np.mean(test_input, axis = 0)
test_std = np.std(test_input, axis = 0)
test_scaled = (test_input - test_mean) / test_std

# 모델 정확도 확인
kn.score(test_scaled, test_target)

# 새로운 데이터를 제대로 예측했음을 확인할 수 있음
print(kn.predict([new_data]))

# 특성값을 표준 점수로 변환한 후 최근접 이웃을 다시 구해보기
# 이웃 데이터들이 모두 도미로 이루어짐 -> 정확한 예측이 가능해짐
distances, indexes = kn.kneighbors([new_data])
plt.scatter(train_scaled[:, 0], train_scaled[:, 1])
plt.scatter(new_data[0], new_data[1], marker = '^')
plt.scatter(train_scaled[indexes, 0], train_scaled[indexes, 1], marker = 'D')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()