본문 바로가기

프로그래밍/AI

[혼공머신 11기] 1주차 스터디 및 과제

반응형

평소에 잘 보지 않는 개인메일을 보다가 우연히 한빛미디어 혼공학습단 11기 모집 소식을 보았다.
그동안 관심은 있었으나 업무와 육아 핑계로 미루거나 업무 관련 스터디만 하느라 쉽게 접근하지 못했던 "머신러닝+딥러닝" 책이 보여서 신청했다.
앞으로 6주 동안 미루지 말고 힘내보자!


기본미션 : 코랩 실습화면 캡쳐하기

일부 캡쳐

전체 실행 결과
https://gist.github.com/hyunto/7932f7cc286a1d5f3f31796a5d13ebf4

선택미션 : Ch.02(02-1) 확인 문제 풀고, 풀이 과정 정리하기


01. 나의 첫 머신러닝

생선 분류 문제

판매할 생선 목록

  • 도미
  • 곤들매기
  • 농어
  • 강꼬치고기
  • 로치
  • 빙어
  • 송어

보통 프로그램은 '누군가 정해준 기준대로 일'을 한다.
반대로 머신러닝은 누구도 알려주지 않은 기준을 찾아서 일을 한다.

k-최근접 이웃 알고리즘

  • 어떤 데이터에 대한 답을 구할 때, 주위의 다른 데이터를 보고 다수를 차지하는 것을 정답으로 사용한다.
  • 새로운 데이터에 대해 예측할 때는 가장 가까운 직선거리에 어떤 데이터가 있는지를 살핀다.
  • 데이터가 아주 많은 경우에는 메모리가 많이 필요하고, 직선거리 계산에 많은 시간이 필요하기 때문에 사용하기 어렵다.

실습

Code

import matplotlib.pyplot as plt

# 도미의 길이(cm)
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]
# 도미의 무게(g)
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]

# 빙어의 길이(cm)
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]
# 빙어의 무게(g)
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')    # x축은 길이
plt.ylabel('weight')    # y축은 무게
plt.show()

###
# 첫 번째 머신러닝 프로그램
###
# 1. 생선 데이터 준비 (49개)
length = bream_length + smelt_length
weight = bream_weight + smelt_weight

fish_data = [[l, w] for l, w in zip(length, weight)]
print("### 생선 데이터 ###")
print(fish_data)
print()

# 2. 정답 데이터 준비 (1: 도미, 0: 빙어)
fish_target = [1] * 35 + [0] * 14
print("### 정답 데이터 (1: 도미, 0: 방어) ###")
print(fish_target)
print()

# 3. 사이킷런 패키지의 k-최근접 이웃 알고리즘 사용
from sklearn.neighbors import KNeighborsClassifier

kn = KNeighborsClassifier()
kn.fit(fish_data, fish_target)  # 훈련
print("### 훈련 평가 ###")
print(kn.score(fish_data, fish_target))  # 평가 : 0~1 사이의 값 반환. 정확도. 1.0은 모든 데이터를 정확하게 맞췄음을 의미.
print()

print("### 생선의 종류 판단 ###")
print(kn.predict([[30, 600]])) # 1(도미) 반환
print()

# 4. k-최근접 이웃 알고리즘의 참고 데이터 변수를 변경하여 사용
kn49 = KNeighborsClassifier(n_neighbors=49)
kn49.fit(fish_data, fish_target)
print("### 참조 데이터 개수를 49개로 설정할 때의 훈련 평가 ###")
print(kn49.score(fish_data, fish_target))
print()
print("### 참조 데이터 개수를 49개로 설정할 때의 생선 종류 판단 ###")
print(kn49.predict([[30, 600]])) # 1(도미) 반환

Colab 실행결과

02. 데이터 다루기 : 02-1. 훈련 세트와 테스트 세트

용어 정리

  • 입력(input) : 데이터
  • 타깃(target) : 정답
  • 훈련 데이터(training data) : 데이터 + 정답
  • 특성(feature) : 입력으로 사용된 데이터를 표현하는 성질

지도 학습 vs. 비지도 학습

머신러닝 알고리즘은 크게 지도 학습(supervised learnling)비지도 학습(unsupervised learning)으로 나눌 수 있다.

  • 지도 학습
    • 훈련하기 위한 데이터와 정답이 필요하다.
    • 정답(target)이 있으니 알고리즘이 정답을 맞히는 것을 학습한다.
  • 비지도 학습
    • 정답(target) 없이 입력 데이터만 사용한다.
    • 입력 데이터에서 어떤 특징을 찾는데 주로 활용한다.
  • 강화 학습(reinforcement learning)
    • 정답(target)이 아니라 알고리즘이 행동한 결과로 얻은 보상을 사용해 학습된다.

훈련 세트와 테스트 세트

머신러닝 알고리즘의 성능을 제대로 평가하려면 훈련 데이터와 평가에 사용할 데이터가 각각 달라야 한다.

  • 훈련 세트(train set) : 훈련에 사용되는 데이터. 데이트가 클수록 좋다.
  • 테스트 세트(test set) : 평가에 사용하는 데이터

실습

잘못된 테스트 세트 추출로 인한 샘플링 편향 예제

Code

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

from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()

# 훈련 세트 입력값 35개 (0~34번째 인덱스)
train_input = fish_data[:35]

# 훈련 세트 타깃값 35개 (0~34번째 인덱스)
train_target = fish_target[:35]

# 테스트 세트로 입력값 14개 (35~마지막 인덱스)
test_input = fish_data[35:]

# 테스트 세트로 타깃값 14개 (35~마지막 인덱스)
test_target = fish_target[35:]

# 입력값에는 도미만, 타깃값에는 빙어만 포함되어 있다. - 문제점!!
# 샘플링 편향(sampling bias)으로 인해 정확도가 0.0이다.
kn = kn.fit(train_input, train_target)
print("### 샘플링 편향 ###")
print(f"정확도 : {kn.score(test_input, test_target)}")
print()

Colab 실행결과

데이터를 랜덤으로 섞어 테스트 세트 추출 후 결과

Code

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

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

input_arr = np.array(fish_data)
target_arr = np.array(fish_target)

print("### numpy의 {array}.shapre 속성은 (샘플 수, 특성 수)를 출력한다. ###")
print(input_arr.shape)
print()

np.random.seed(42)
index = np.arange(49)
np.random.shuffle(index)

print("### 랜덤 인덱스 ###")
print(index)
print()

# 훈련 세트
train_input = input_arr[index[:35]]
train_target = target_arr[index[:35]]

# 테스트 세트
test_input = input_arr[index[35:]]
test_target = target_arr[index[35:]]

plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(test_input[:,0], test_input[:,1])
plt.xlabel('length')
plt.ylabel('weight')
print("### 훈련 세트와 테스트 세트 산점도 ###")
plt.show()
print()

# 훈련 세트와 테스트 세트로 k-최근접 이웃 모델 훈련
kn = kn.fit(train_input, train_target)
print("### 훈련 평가 ###")
print(kn.score(test_input, test_target))
print()

print("### 실제 타깃 데이터와 예측 결과 ###")
print(f"실제 타깃 : {test_target}")
print(f"예측 결과 : {kn.predict(test_input)}")

Colab 실행결과

02. 데이터 다루기 : 02-2. 데이터 전처리

넘파이

  • seed()
  • arange()
  • shuffle()
  • column_stack()
  • ones()
  • zeros()
  • concatenate()
  • mean()
  • std()

데이터 전처리

  • 스케일(scale)
    • 두 특성 (ex> 생선의 길이와 무게)
  • 문제점
    • 특성 간 스케일이 다르다.
      즉, 데이터를 표현하는 기준이 다르다.
    • 스케일이 다르면 알고리즘이 올바르게 예측할 수 없다.
  • 데이터 전처리 (data preprocessing)
    • k-최근접 이웃 알고리즘 같은 거리 기반 알고리즘은 샘플 간의 거리에 영향을 많이 받는다.
    • 알고리즘을 제대로 사용하려면 특성값을 일정한 기준으로 맞춰야 하는데, 이를 데이터 전처리라고 한다.
    • 가장 널리 사용하는 전처리 방법은 표준 점수(standard score) 이다.
      이를 통해 실제 특성값의 크기와 상관없이 동일한 조건으로 비교할 수 있다.
    • 계산 방법 : 원본에서 평균을 빼고, 표준편차를 나눈다.
    • 주의할 점 : 훈련 세트와 테스트 세트 모두 변환해야 한다.

실습

Code

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

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 = np.column_stack((fish_length, fish_weight))
fish_target = np.concatenate((np.ones(35), np.zeros(14)))

# 사이킷런으로 훈련 세트와 테스트 세트 나누기
train_input, test_input, train_target, test_target = train_test_split(fish_data, fish_target, random_state=42)
print(f"테스트 타깃 : {test_target} - 빙어의 비율이 조금 부족하다!")

# train_test_split() 함수의 stratify 매개변수를 사용하여 샘플링 편향 방지
#   - 도미 35개, 빙어 14개 - 2.5:1
#   - stratify 사용 전 비율 : 3.3:1
#   - stratify 사용 후 비율 : 2.25:1
train_input, test_input, train_target, test_target = train_test_split(fish_data, fish_target, stratify=fish_target, random_state=42)
print(f"테스트 타깃 : {test_target} - 빙어를 하나 추가하여 비율을 조절했다")
print()

# k-최근접 이웃 훈련
kn = KNeighborsClassifier()
kn.fit(train_input, train_target)
print(f"k-최근접 이웃 훈련 모델 평가 결과 : {kn.score(test_input, test_target)}")

# 수상한 도미 한 마리 테스트...
print(f"수상한 도미 한 마리 : {kn.predict([[25, 150]])} - 1(도미)을 예상했으나 0(빙어)이 나옴")
print()

# 산점도
plt.scatter(train_input[:,0], train_input[:,1])
plt.scatter(25, 150, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
print("### 수상한 도미 한 마리를 포함한 산점도 ###")
plt.show()

# k-최근접 이웃 알고리즘 - 최근접 샘플 구해오기
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')
print("### 분류 테스트하려는 도미와 최근접한 5개 샘플을 표시하는 산점도 ###")
plt.show()
print()

print("### distances 배열 출력 - 무언가 이상하다! ###")
print(distances)
print()

# 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')
print("### x축, y축 범위를 동일하게 조절한 산점도 ###")
plt.show()
print()

# 데이터 전처리
mean = np.mean(train_input, axis=0) #  평균 계산
std = np.std(train_input, axis=0) # 표준편차 계산

train_scaled = (train_input - mean) / std
test_scaled = (test_input - mean) / std
new_scaled = ([25, 150] - mean) / std

# 전처리 데이터로 모델 훈련하기
kn.fit(train_scaled, train_target)
print(f"k-최근접 이웃 훈련 모델 평가 결과 : {kn.score(test_scaled, test_target)}")
print(f"수상한 도미 한 마리 : {kn.predict([new_scaled])} - 예상대로 1(도미) 예측")

distances, indexes = kn.kneighbors([new_scaled])
plt.scatter(train_scaled[:,0], train_scaled[:,1])
plt.scatter(new_scaled[0], new_scaled[1], marker='^')
plt.scatter(train_scaled[indexes,0], train_scaled[indexes,1], marker='D')
plt.xlabel('length')
plt.ylabel('weight')
print("### 전처리 데이터로 훈련된 모델 산점도 ###")
plt.show()
print()

Colab 실행결과

 

 

반응형