유성이의 공부일지(17-2) - 혼자공부하는 머신러닝 + 딥러닝 2장

2024. 9. 21. 16:45·공부 기록일지

02-2. 데이터 전처리

넘파이로 데이터 준비하기
 

코드 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]

 
코드 2 - 넘파이 임포트 하기

import numpy as np

 
코드 3 - 넘파이 colmn_stack() 함수 사용

np.column_stack(([1,2,3], [4,5,6])) // array([[1, 4], [2, 5], [3, 6]])

 
- 넘파이 colmn_stack() 함수는 전달받은 리스트를 일렬로 세운 다음 차례대로 연결함
- 연결할 리스트는 튜플로 전달
- [1,2,3] 과 [4,5,6] 두 리스트를 일렬로 세운 다음 나란히 옆으로 붙음
- 만들어진 배열은 (3,2) 크기의 배열임
 
중요!!

튜플(tuple) 이란?
파이썬의 리스트와 비슷하며, 리스트처럼 원소에 순서가 있지만 한 번 만들어진 튜플은 수정이 안됨!!
튜플을 사용하면 함수로 전달한 값이 바뀌지 않는다는 것을 믿을 수 있기에 매개변수 값으로 많이 사용함

 
코드 4 - fish_length와 fish_weight를 합침

fish_data = np.column_stack((fish_length, fish_weight))

 
코드 5 - 두 리스트가 잘 연결되었는지 5개의 데이터를 확인

print(fish_data[:5]) 

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

 
- 넘파이 배열을 출력하면 리스트처럼 한 줄로 길게 출력되지 않고 행과 열을 맞추어 가지런히 정리된 모습이 보임
- 결과만 봐도 5개의 행을 출력했고 행마다 2개의 열(생선의 길이와 무게)이 있다는 것을 알수 있음
 
코드 6 - np.ones()와 np.zeros() 함수를 이용한 타깃 데이터

print(np.ones(5)) # [1. 1. 1. 1. 1.]

 
- 이 두 함수를 사용해 1이 35개인 배열과 0이 14개인 배열을 만들 수 있음
- 그다음 두 배열을 그대로 사용하면 됨
 
코드 7 - np.concatenate() 함수를 사용한 타깃데이터

fish_target = np.hstack((np.ones(35), np.zeros(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.]

 

사이킷런으로 훈련 세트와 데이터 세트 나누기

 
- 사이킷런은 머신러닝 모델을 위한 알고리즘 뿐만 아니라 다양한 유틸리티 도구도 제공함
- 대표적인 도구가 train_test_split() 함수임
- 이 함수는 전달되는 리스트나 배열을 비율에 맞게 훈련 세트와 데이터 세트로 나누어 줌
 
코드 8 - 사이킷런의 model_selection import 하기

from sklearn.model_selection import train_test_split

 
- 사용버은 나누고 싶은 리스트나 배열을 원하는 만큼 전달하면 됨
- 여기서는 fish_data와 fish_target으로 나눔
- train_test_split() 함수는 친절하게도 자체적으로 랜덤시드를 지정할 수 있는 random_state 매개변수가 있음
 
코드 9 - 훈련세트와 데이터 세트로 나누기

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

 
- fish_data와 fish_target 2개의 배열을 전달했으므로 2개씩 나뉘어 총 4개의 배열이 반환됨
- 차례대로 처음 2개는 입력 데이터(train_input, test_input) 
- 나머지는 타깃 데이터(train_target, test_target)임
- 랜덤 시드(random_state)는 42로 저장함
 
코드 10 - 넘파이 배열의 shape 속성으로 입력 데이터 출력하기

print(train_input.shape, test_input.shape) # (36, 2) (13, 2)
print(train_target.shape, test_target.shape) # (36,) (13,)

 
- 훈련 데이터와 입력 데이터는 각각 36개와 13개로 나눔
- 입력 데이터는 2개의 열이 있는 2차원 배열이고 타깃 데이터는 1차원 배열임
 
코드 11 - 테스트 데이터 출력하기

print(test_target) # [1. 0. 0. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1.]

 
- 13개의 테스트 세트 중에 10개가 도미(1)이고, 3개가 방어(0) 임
- 잘 섞인것 같지만 빙어의 비율이 조금 모자람
- 이 테스트 세트의 도미와 빙어의 비율은 3.3:1임
- 이렇게 되면 샘플링 편향도 나타남
 
코드 12 - stratify 매개변수에 타깃 데이터 전달하기

train_input, test_input, train_target, test_target = train_test_split(fish_data, fish_target, stratify=fish_target, random_state=42)
print(test_target) # [0. 0. 1. 0. 1. 0. 1. 1. 1. 1. 1. 1. 1.]

 
- 빙어가 하나 더 늘어 테스트 세트 비율이 2.25:1이 됨
 

수상한 도미 한마리
 

코드 13 - k- 최근접 이웃 알고리즘 훈련

from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
kn.fit(train_input, train_target)
kn.score(test_input, test_target)
# 1.0

 
- 완벽한 결과가 나왔음
- 테스트 세트의 도미와 빙어를 올바르게 분류함
 
코드 14 - 예측 데이터 확인하기

print(kn.predict([[25, 150]])) # [0.]

 
- 이 데이터가 올바른지 의심됨
- 그래서 산점도를 이용한 데이터를 그려봄
 
코드 14 - 산점도를 이용한 데이터 그리기

import matplotlib.pyplot as plt
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(25, 150, marker='^') # marker 매개변수는 모양을 지정합니다
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

 
- 새로운 샘플은 maker 매개변수를 ^로 지정하여 삼각형으로 나타냄
- 이렇게 하면 구분하기 더 쉬워짐
- k- 최근접 이웃은 주변의 샘플 중에서 다수의 클래스를 예측으로 사용함
- KNeighborsClassifier 클래스는 주어진 샘플에서 가장 가까운 이웃을 찾아주는 Kneighbors() 매서드 제공
- 이 메서드는 이웃까지의 거리와 이웃 샘플의 인덱스를 반환함
- KNeighborsClassifier 클래스의 이웃 개수인 n_neighbors의 기본값은 5이므로 5개의 이웃이 반환됨
 

distances, indexes = kn.kneighbors([[25, 150]])

 
코드 15 - indexes 배열을 사용해 훈련 데이터 중에서 이웃 샘플 그리기

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()

 
- maker='D'로 지정하면 산점도를 마름모로 그림
- 삼각형 샘플에 가까운 5개의 샘플이 초록 다이아몬드에 표시됨
- 예측 결과와 마찬가지로 가장 가까운 아웃에 도미가 하나밖에 포함 됨
- 나머지 4개의 샘플은 모두 빙어
 
코드 16 - 샘플 빙어 확인하기(1)

print(train_input[indexes])
# [[[ 25.4 242. ]
  [ 15.   19.9]
  [ 14.3  19.7]
  [ 13.   12.2]
  [ 12.2  12.2]]]

 
코드 17 - 샘플 빙어 확인하기(2)

print(train_target[indexes]) # [[1. 0. 0. 0. 0.]]

 
- 길이가 25cm, 무게가 150g인 생선에 가장 가까운 이웃에는 빙어가 압도적으로 많음
- 따라서 이 샘플의 클래스를 빙어로 예측하는 것은 무리가 아님
 
코드 18 - 샘플 빙어 확인하기(3)

print(distances)
# [[ 92.00086956 130.48375378 130.73859415 138.32150953 138.39320793]]

 
기준을 맞춰라

 
코드 19 - 확률에 맞는 기준 맞추기

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()

 
- 산점도가 거의 일직선으로 나타내는 x축과 y축의 범위를 동일하게 맞춤
- 모든 데이터가 수직으로 늘어선 형태가 됨
- 이런 데이터는 생선의 길이(x축)은 가장 가까운 이웃을 찾는 데 크게 영향을 미치지 못함 
- 오로지 생선의 무게(y축)만 고려 대상이 됨
- 두 특성(길이와 무게)의 값이 놓인 범위가 매우 다름
- 두 특성의 스케일이 다르다고 말함
 
데이터 전처리
알고리즘이 샘플 간의 거리에 영향을 받은데, 제대로 사용하려면 특성값을 일정한 기준으로 맞춰야 함
 
표준점수란?
각 특성값이 0에서 표준편차의 몇 배만큼 떨어져 있는지를 나타냄
이를 통해서 실제 크기와 상관없이 동일한 조건으로 비교가능
 
코드 20 - 표준점수와 표준편차 계산(1)

mean = np.mean(train_input, axis=0) // 평균을 계산
std = np.std(train_input, axis=0) // 표준편차 계산

 
- 특성마다 값의 스케일이 다르므로 평균과 표준편차는 각 특성별로 계산해야 함
- 이를 위해 axis = 0으로 지정함
 
코드 21 - 표준점수와 표준편차 계산(2)

print(mean, std)
# [ 27.29722222 454.09722222] [  9.98244253 323.29893931]
train_scaled = (train_input - mean) / std

 
- 각 특성마다 평균과 표준편차가 구해짐
- 넘파이는 똑똑하게도 train_input에 있는 모든 행에서 mean에 있는 평균값을 빼줌
- 그다음 std에 있는 두 표준편차를 다시 모든 행에 적용함
- 이런 넘파이 기능을 브로드캐스팅 이라고 함
 

전처리 데이터로 모델 훈련하기
 

코드 22 - 앞써 데이터의 샘플을 산점도로 그리기

plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(25, 150, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

 
- 이 값에서 틀린 부분이 있음
- 오른쪽 맨 꼭대기에 수상한 샘플 하나만 덩그러니 떨어져 있음
- 이런 이유는 훈련 세트를 mean(평균) - std(표준편차)로 나누어 주었기 때문
- 샘플 [20, 150]을 동일한 비율로 변환하지 않았기에 이런 현상이 발생함
 

코드 23 - 훈련세트의 mean, std를 이용해서 산점도 그리기

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

 
- 이그래프는 앞서 표준편차로 변환하기 전의 산점도와 거의 비슷함
- 크게 달라진 점은 축의 범위가 -1.5 ~ 1.5 사이로 바뀜
- 훈련 데이터의 두 특성이 비슷한 범위를 차지하고 있음
 
코드 24 - 위의 데이터셋으로 k-최근점 이웃 모델 훈련

kn.fit(train_scaled, train_target)

 
- 훈련을 마치고 테스트 세트로 평가할 때는 주의해야 함
- 테스트 세트도 훈련 세트의 평균과 표준 편차를 변환해야 함
- 그렇지 않으면 데이터의 스케일이 같아지지 않으므로 훈련한 모델이 쓸모없게 됨
 
코드 25 - 테스트 세트의 스케일 변환

test_scaled = (test_input - mean) / std

 
코드 26 - 모델 평가

kn.score(test_scaled, test_target) # 1.0

 
- 모든 테스트 세트의 샘플을 완벽하게 분류해냄
 
코드 27 - 최종 평가(1)

print(kn.predict([new])) # [1.]

 
- 도미(1)로 예측하게 됨
- 확실히 길이가 25cm이고, 무게가 150인 생선은 도미임
 
코드 28 - 최종 평가(2)

distances, indexes = kn.kneighbors([new])
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(new[0], new[1], marker='^')
plt.scatter(train_scaled[indexes,0], train_scaled[indexes,1], marker='D')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

 
- 샘플에서 가장 가까운 샘플은 모두 도미임
- 따라서 이 수상한 샘플을 도미로 예측하는 것은 당연한것
- 특성값의 스케일에 민감하지 않고 안정적인 예측을 할 수 있는 모델임
 
코드 29 - 총 정리

"""# 데이터 전처리"""

"""## 넘파이로 데이터 준비하기"""

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

np.column_stack(([1,2,3], [4,5,6]))

fish_data = np.column_stack((fish_length, fish_weight))

print(fish_data[:5])

print(np.ones(5))

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

print(fish_target)

"""## 사이킷런으로 훈련 세트와 테스트 세트 나누기"""

from sklearn.model_selection import train_test_split

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

print(train_input.shape, test_input.shape)

print(train_target.shape, test_target.shape)

print(test_target)

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

print(test_target)

"""## 수상한 도미 한 마리"""

from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
kn.fit(train_input, train_target)
kn.score(test_input, test_target)

print(kn.predict([[25, 150]]))

import matplotlib.pyplot as plt
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(25, 150, marker='^') # marker 매개변수는 모양을 지정합니다
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

distances, indexes = kn.kneighbors([[25, 150]])

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()

print(train_input[indexes])

print(train_target[indexes])

print(distances)

"""## 기준을 맞춰라"""

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)

print(mean, std)

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 = ([25, 150] - mean) / std
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(new[0], new[1], marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

kn.fit(train_scaled, train_target)

test_scaled = (test_input - mean) / std

kn.score(test_scaled, test_target)

print(kn.predict([new]))

distances, indexes = kn.kneighbors([new])
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(new[0], new[1], marker='^')
plt.scatter(train_scaled[indexes,0], train_scaled[indexes,1], marker='D')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

'공부 기록일지' 카테고리의 다른 글

유성이의 공부일지(18-1) - 혼자공부하는 머신러닝 + 딥러닝 3장  (0) 2024.10.11
유성이의 공부일지(17-1) - 혼자공부하는 머신러닝 + 딥러닝 2장  (1) 2024.09.07
유성이의 공부일지(16) - 혼자공부하는 머신러닝 + 딥러닝 1장  (3) 2024.08.27
유성이의 공부일지(15) - 혼자공부하는 컴퓨터 구조 + 운영체제 15장  (0) 2024.07.16
유성이의 공부일지(14) - 혼자공부하는 컴퓨터 구조 + 운영체제 14장  (0) 2024.07.15
'공부 기록일지' 카테고리의 다른 글
  • 유성이의 공부일지(18-1) - 혼자공부하는 머신러닝 + 딥러닝 3장
  • 유성이의 공부일지(17-1) - 혼자공부하는 머신러닝 + 딥러닝 2장
  • 유성이의 공부일지(16) - 혼자공부하는 머신러닝 + 딥러닝 1장
  • 유성이의 공부일지(15) - 혼자공부하는 컴퓨터 구조 + 운영체제 15장
메테오유성
메테오유성
유성이가 하고 싶은 이야기를 올리는 일기장
  • 메테오유성
    유성의 이것저것
    메테오유성
  • 전체
    오늘
    어제
    • 분류 전체보기 (32)
      • IT & Tech 이야기 (3)
      • 디자인 (0)
      • 공부 기록일지 (19)
      • 책 기록일지 (0)
      • UX 연구 & 리서치 노트 (9)
      • 알고리즘 스터디 기록 (0)
      • 음악 추천🎧 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    apple
    포스텔의 법칙
    대기 큐
    it
    운영체제
    유비쿼스트 결제 프로세스
    테스트 세트
    WWDC
    스레드
    train_test_split()
    자동인지 처리
    ferret-ui
    변화 무시
    배너 무시
    샘플 레이아웃 패턴
    우선순위 스케줄링
    메일 침프
    심미적 사용성 효과
    Google
    교착 상태 예방
    여정 지도
    kneighbors()
    디자인 작업 프로세스
    타조 알고리즘
    rr 스케줄링
    선택적 주의력
    도허티의 임계
    테슬러의 법칙
    디자인 회복 탄성력
    폰 레스토프 효과
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
메테오유성
유성이의 공부일지(17-2) - 혼자공부하는 머신러닝 + 딥러닝 2장
상단으로

티스토리툴바