혼공 ML+DL

1주차 Chapter 01 (나의 첫 머신러닝), Chapter 02 (데이터 다루기)

채영sw 2024. 1. 31. 17:36

 

 

GitHub - rickiepark/hg-mldl: <혼자 공부하는 머신러닝+딥러닝>의 코드 저장소입니다.

<혼자 공부하는 머신러닝+딥러닝>의 코드 저장소입니다. Contribute to rickiepark/hg-mldl development by creating an account on GitHub.

github.com

 

 

혼자 공부하는 머신러닝+딥러닝

이 책은 수식과 이론으로 중무장한 머신러닝, 딥러닝 책에 지친 ‘독학하는 입문자’가 ‘꼭 필요한 내용을 제대로’ 학습할 수 있도록 구성 되어 있습니다. 구글 머신러닝 전문가(Google ML expert)

www.youtube.com

Chapter 01

1-1. 인공지능과 머신러닝, 딥러닝

  • 인공지능 : 학습하고 추론할 수 있는 지능을 가진 컴퓨터 시스템을 만드는 기술
  • 머신러닝 : 데이터에서 규칙을 학습하는 알고리즘을 연구하는 분야
  • 딥러닝 : 인공신경망을 기반으로 한 머신러닝 분야

1-2. 코랩과 주피터 노트북

  • 코랩 : 웹 브라우저에서 텍스트와 프로그램 코드를 자유롭게 작성 할 수 있는 온라인 에디터로 이를 코렙 노트북 또는 노트북이라 부름.
    • 최소단위 : 셀 (코드 셀 / 텍스트 셀)

1-3. 마켓과 머신러닝

  • 분류 : 머신러닝에서 여러 개의 종류(or 클래스) 중 하나를 구별해 내는 문제
  • 이진 분류(binary classification) : 2개의 종류(클래스) 중 하나를 고르는 문제
  • 특성(feature) : 데이터를 표현하는 특징
  • 맷플롯립(matplotlib) : 파이썬에서 과학계산용 그래프를 그리는 대표 패키지
  • k-최근접 이웃 알고리즘(k-Nearest Neighbors Algorithm, KNN) : 가장 간단한 머신러닝 알고리즘 중 하나로 어떤 규칙을 찾기보다는 인접한 샘플을 기반으로 예측을 수행함
  • 훈련(training) : 머신러닝 알고리즘이 데이터에서 규칙을 찾는 과정 또는 모델에 데이터를 전달하여 규칙을 학습하는 과정

 

  • 생선 분류 문제
#도미 데이터 준비
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]

산점도 : x, y축으로 이뤄진 좌표계에 두 변수의 관계를 표현하는 방법 -> 맷플롯립(matplotlib) 이용

import matplotlib.pyplot as plt #matplotlib의 pylot 함수를 plt로 줄여서 사용

plt.scatter(bream_length, bream_weight)
plt.xlabel('length') #x축 길이
plt.ylabel('weight') #y축 무게
plt.show()

선형적 : 산점도 그래프가 일직선에 가까운 형태로 나타나는 경우

#빙어 데이터 준비하기
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]
plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

 

색으로 구분

 

 

#하나의 리스트로 만들기
length = bream_length+smelt_length
weight = bream_weight+smelt_weight

머신러닝 패키지 사이킷런(scikit-learn)을 사용하기 위해 리스트를 세로방향으로 늘어뜨린 2차원 리스트로 만들어야함.

#zip() 함수(나열된 리스트 각각에서 하나씩 원소를 꺼내 반환)와 리스트 내포 구문 사용
fish_data = [[l, w] for l, w in zip(length, weight)]

print(fish_data)

출력 예시

#정답 리스트 만들기
fish_target = [1]*35 + [0]*14
print(fish_target)

 

출력 예시

#사이킷런  패키지에서 KNN을 구현한 클래스인 KNeighborsClassifier를 임포트함.
from sklearn.neighbors import KNeighborsClassifier
#객체 만들기
kn = KNeighborsClassifier()
#사이킷런에서 fit() 메서드가 머신러닝 훈련 역할을 함.
kn.fit(fish_data, fish_target)
#정확도 측정
kn.score(fish_data, fish_target)

 

새로운 데이터 분류해보면

plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.scatter(30, 600, marker='^') #삼각형 모양
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
#새로운 데이터의 정답 예측
kn.predict([[30, 600]])
#x,y 속성 데이터
print(kn._fit_X)
print(kn._y)

 

참고 데이터를 49개로 한다면 도미가 다수를 차지하므로 어떤 데이터를 넣어도 무조건 도미로 예측됨.

kn49 = KNeighborsClassifier(n_neighbors=49)
kn49.fit(fish_data, fish_target)
kn49.score(fish_data, fish_target)

print(35/49)

 

 

Chapter 02

2-1. 훈련 세트와 테스트 세트

  •  지도 학습 : 입력(데이터)과 타깃(정답)으로 이뤄진 훈련 데이터가 필요하며 새로운 데이터를 예측하는 데 활용함.
  • 비지도 학습 : 타깃 데이터 없이 입력 데이터만 있을 때 사용
  • 훈련 데이터 : 지도 학습의 경우 필요한입력(데이터)과 타깃(정답)을 합쳐 놓은 것
  • 훈련 세트(train set) / 테스트 세트(test set) : 모델을 훈련할 때는 훈련 세트를, 평가할 때는 테스트 세트를 사용함.
  • 샘플링 편향(sampling bias) : 훈련 세트와 테스트 세트에 샘플이 고르게 섞여 있지 않을 때 나타남
  • 넘파이(NumPy) : 파이썬의 대표적인 배열 라이브러리로 고차원의 배열을 손쉽게 만들고 조작할 수 있는 간편한 도구를 많이 제공함.
#리스트 준비하기
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 = [[l, w] for l, w in zip(fish_length, fish_weight)]
fish_target = [1]*35 + [0]*14
#KNeighborsClassifier 클래스를 임포트하고 모델 객체 만들기
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()

 

슬라이싱으로 train set, test set 선택

train_input = fish_data[:35]
train_target = fish_target[:35]

test_input = fish_data[35:]
test_target = fish_target[35:]
#fit()으로 모델 훈련, score()으로 평가
kn.fit(train_input, train_target)
kn.score(test_input, test_target)

-> 0.0 정확도 0 나옴!

왜? -> 샘플링 편향 때문! -> NumPy 사용으로 해결

import numpy as np
#리스트를 넘파이 배열로 바꾸기 -> array() 함수 사용
input_arr = np.array(fish_data)
target_arr = np.array(fish_target)
print(input_arr) # 배열 출력
print(input_arr.shape) #샘플 수, 특성 수 출력
np.random.seed(42) #무작위 결과를 만드는 함수들을 실행할 때 일정한 결과를 얻으려면 초기에 랜던 시드(random seed)를 지정해야 함
index = np.arange(49) #arange() 함수로 1씩 증가하는 인덱스 만들 수 있음
np.random.shuffle(index) #shuffle()함수로 주어진 배열을 무작위로 섞음 -> 인덱스 무작위

 

무작위 index 배열을 훈련 세트로 만들기

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

 

무작위 index 배열을 테스트 세트로 만들기

 

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.xlabel('length')
plt.ylabel('weight')
plt.show()

훈련, 테스트 세트가 잘 섞인 것을 확인할 수 있음.

kn.fit(train_input, train_target)
kn.score(test_input, test_target)
kn.predict(test_input) #결과 예측
test_target #예측 맞는지 확인

 

2-2. 데이터 전처리

  • 데이터 전처리(data preprocessing) : 머신러닝 모델에 훈련 데이터를 주입하기 전 가공하는 단계로 특성값을 일정한 기준으로 맞추어 주는 작업
  • 브로드캐스팅(broadcasting) : 조건을 만족하면 모양이 다른 배열 간의 연산을 가능하게 해 주는 기능
#넘파이로 데이터 준비하기
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
#column_stack() 함수 : 전달받은 리스트를 일렬로 세운 다음 차례대로 나란히 연결함.
fish_data = np.column_stack((fish_length, fish_weight))
#np.ones(), np.zeros() : 원하는 개수의 1과 0을 채운 배열을 만들어줌.
fish_target = np.concatenate((np.ones(35), np.zeros(14)))
print(fish_target)

 

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

from sklearn.model_selection import train_test_split
# 랜덤 시드를 42로 지정, 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)

빙어의 비율이 모자람

#stratify 매개변수에 타깃 데이터를 전달하면 클래스 비율에 맞게 데이터를 나눔
train_input, test_input, train_target, test_target = train_test_split(
    fish_data, fish_target, stratify=fish_target, random_state=42)

 

수상한 도미 한마리

#훈련 & 평가
from sklearn.neighbors import KNeighborsClassifier

kn = KNeighborsClassifier()
kn.fit(train_input, train_target)
kn.score(test_input, test_target)
import matplotlib.pyplot as plt
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()

#kn.kneighbors()함수 : 주어진 샘플에서 가장 가까운 이웃을 찾아주는 메서드
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()

 

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

두 특성의 스케일이 다르면 특성값을 일정한 기준으로 맞춰 주어야 함 -> 데이터 전처리

  • 표준 점수 : 가장 널리 사용하는 전처리 방법 중 하나, 각 데이터가 원점에서 몇 표준편차만큼 떨어져 있는지를 나타냄.
  • 분산: 데이터에서 평균을 뺸 값을 모두 제곱한 다음 평균을 내 구함
  • 표준편차 : 분산의 제곱근으로 데이터가 분산된 정도를 나타냄
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 = ([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)
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()

새로운 샘플에서 가장 가까운 샘플은 모두 도미임을 알 수 있음