반응형
평소에 잘 보지 않는 개인메일을 보다가 우연히 한빛미디어 혼공학습단 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 실행결과