촉촉한초코칩
[혼공머신] Ch01, 2 본문
https://gist.github.com/rickiepark
Ch 01 나의 첫 머신러닝
- 인공지능, 머신러닝, 딥러닝 차이점
- 머신러닝 기본 동작 원리
01-1 인공지능과 머신러닝, 딥러닝
인공지능 (Artifical Intelligence)
: 사람처럼 학습하고 추론할 수 있는 지능을 가진 컴퓨터 시스템을 만드는 기술
인공 일반지능(강인공지능) Artificial General Intelligence
: 사람과 구분하기 어려운 지능을 가진 컴퓨터 시스템
약인공지능 (Week AI)
: 특정 분야에서 사람의 일을 도와주는 보조 역할을 하는 컴퓨터 시스템
머신러닝 (Machine Learning)
: 자동으로 데이터에서 규칙을 학습하는 알고리즘을 연구하는 분야 ex) R언어, 사이킷런 라이브러리
딥러닝 (Deep Learning)
: 머신러닝 알고리즘 중 인공 신경망을 기반으로 한 알고리즘 ex) 텐서플로, 파이토치 라이브러리
01-2 코랩과 주피터 노트북
01-3 마켓과 머신러닝
k-최근접 이웃 사용하여 2개의 종류를 분류하는 머신러닝 모델 훈련
문제 : 생선 이름을 자동으로 알려주는 머신러닝
→ 머신러닝이 스스로 기준을 만들어서 분류할 수 있도록 함
* 클래스 : 여러 개의 종류
* 분류 : 클래스 중 하나를 구별하는 문제 → 이진 분류
k-최근점 이웃 (k-Nearest Neighbors) 알고리즘
- k-최근접 이웃 분류 모델 만드는 사이킷런 클래스
- 어떤 데이터에 대한 답을 구할 때 주위의 다른 데이터를 보고 다수를 차지하는 것을 정답으로 사용한다.
새로운 데이터를 예측할 때는 가장 가까운 직선거리에 어떤 데이터가 있는지 살피면 된다. - 훈련 fit() 메서드에 전달한 데이터를 모두 저장하고 있다가 새로운 데이터가 등장하면 가장 가까운 데이터를 n_neighbors 개를 참고하여 결정한다. (n_neighbors 기본값 : 5개)
- 단점 : 데이터가 많은 경우 직선거리를 계산할 때 많은 시간이 필요하다.
- fit() : 모델 훈련. (훈련에 사용할 특성, 정답 데이터)
predict() : 모델 훈련, 예측 (특성 데이터)
score() : 모델 성능 측정 (특성, 정답 데이터)
정확도 = (정확히 맞힌 개수) / (전체 데이터 개수)
#1. 데이터 가져오기
#도미 특성 feature
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] #생선의 길이 x축
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] #생선의 무게 y축
#각 도미를 그래프(산점도 scatter plot)에 점으로 표시한다.
#matplotlib : 과학계산용 그래프 그리는 패키지
import matplotlib.pyplot as plt
plt.scatter(bream_length, bream_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
#선형(Linear) : 산점도 그래프가 일직선에 가까운 형태로 나타나는 경우
#빙어 특성 feature
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]
#각 빙어를 그래프(산점도 scatter plot)에 점으로 표시한다.
plt.scatter(smelt_length, smelt_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
#도미랑 빙어 같이 그리기
plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
#2. 첫번째 알고리즘
length = bream_length + smelt_length
weight = bream_weight + smelt_weight
#사이킷런을 사용하려면 각 특성의 리스트를 세로 방향으로 늘어뜨린 2차원 리스트로 마들어야 한다.
#zip() : 나열된 리스트 각각에서 하나씩 원소를 꺼내 반환한다.
fish_data = [[l, w] for l, w in zip(length, weight)]
print(fish_data)
#정답 데이터 만들기 (어떤 게 도미이고 빙어인지)
#1 : 도미(0~34), 0 : 빙어(35~48)
fish_target = [1] * 35 + [0] * 14
print(fish_target)
#사이킷런 패키지에서 k-최근접 이웃 알고리즘을 구현한 클래스인 KNeighborsClassifier 사용
from sklearn.neighbors import KNeighborsClassifier
#클래스 객체 생성
#훈련 fit() : fish_data와 fish_target을 전달하여 모리르 찾는 기준을 학습시킨다.
kn = KNeighborsClassifier()
kn.fit(fish_data, fish_target)
#score() : 알고리즘 평가 (정확도)
#0~1 사이에서 1에 가까울 수록 정확하게 맞췄다는 것을 의미한다.
kn.score(fish_data, fish_target)
#predict() : 새로운 데이터의 정답 예측
#2차원 리스트이기 때문에 2번 감싼다.
kn.predict([[30, 600]])
print(kn._fit_X) #fish_data
print(kn._fit_y) #fish_target
#fit() 메서드에 전달한 데이터를 모두 저장하고 있다가 새로운 데이터가 등장하면 가장 가까운 데이터를 참고하여 결정한다.
#가까운 몇개의 데이터 참고해서 예측하기
#n_neighbors 기본 값 = 5 > 주변에서 가장 가까운 5개의 데이터를 보고 다수결의 원칙에 따라 데이터 예측
kn49 = KNeighborsClassifier(n_neighbors=49)
kn49.fit(fish_data, fish_target)
kn49.score(fish_data, fish_target)
#score : 0.71 > 도미만 올바르게 맞추는 모델이기 때문에 35/49한 값과 동일하다.
#n_neighbors를 49로 설정하면 점수가 1.0보다 작아, 정확도가 100% 아님을 나타낸다.
n_neighbors의 값을 5~49로 바꾸면서 점수가 1.0 아래로 내려가기 시작하는 이웃의 개수를 찾는다.
kn = KNeighborsClassifier()
kn.fit(fish_data, fish_target)
for n in range(5, 50):
#k-최근접 이웃 개수 설정
kn.n_neighbors = n
#점수 계산
score = kn.score(fish_data, fish_target)
#100% 정확도에 미치지 못하는 이웃 개수 출력
if score < 1:
print(n, score)
break
Ch02 데이터 다루기
- 머신러닝 알고리즘에 주입할 데이터 준비하는 방법
- 데이터 형태가 알고리즘에 미치는 영향
02-1 훈련 세트와 테스트 세트
지도 학습과 비지도 학습의 차이점
모델을 훈련시키는 훈련 세트와 모델을 평가하기 위한 테스트 세트로 데이터를 나눠서 학습한다.
머신러닝 알고리즘 : 지도 학습 (Supervised learning) / 비지도 학습 (Unsupervised learning)
지도학습
- 훈련하기 위한 데이터와 정답 필요
- 데이터와 정답 : 입력(데이터), 타깃(정답) = 훈련 데이터
- 알고리즘 : 정답 맞히는 것 학습
비지도학습
- 알고리즘 : 타깃 없이 입력 데이터만 사용 (입력 데이터만 있을 때 사용)
- 정답을 사용하지 않으므로 무언가를 맞힐 수 없음 대신 데이터를 잘 파악하거나 변형하는 데 도움을 줌
머신러닝 알고리즘의 성능을 제대로 평가하려면 훈련 데이터(훈련 세트)와 평가에 사용할 데이터(테스트 세트)가 달라야 함
→ 또 다른 데이터 준비하기 or 이미 준비된 데이터(훈련 세트) 중에서 일부를 떼어 내어 활용하기
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_weigh = [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차원 리스트 만들기
#하나의 생선 데이터 : 샘플 -> 총 49개의 샘플
#사용하는 특성 : 길이, 무게
fish_data = [[l,w] for l, w in zip(fish_length, fish_weigh)]
#35개 : 훈련 세트
#14개 : 테스트 세트
fish_target = [1]*35 + [0]*14
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
#훈련 세트 입력값 중 0~34번째 인덱스까지 사용
train_input = fish_data[:35]
#훈련 세트 타깃값 중 0~34번째 인덱스까지 사용
train_target = fish_target[:35]
#테스트 세트 입력값 중 35~마지막 인덱스까지 사용
test_input = fish_data[35:]
#테스트 세트 타깃값 중 35~마지막 인덱스까지 사용
test_target = fish_target[35:]
#모델 훈련하고 테스트 세트로 score() 메서드 호출
kn.fit(train_input, train_target)
kn.score(test_input, test_target)
문제점 : 도미, 빙어를 0부터 순서대로 넣었기 때문에 처음 나눈 훈련 세트에는 당연히 빙어가 없음
해결방법 : 훈련, 테스트 세트에 도미와 빙어가 골고루 섞이게 만들어야 함
샘플링 편향 (Sampling bias) : 훈련 세트와 테스트 세트에 샘플이 골고루 섞여 있지 않고 샘플링이 한쪽으로 치우쳐진 것
넘파이 (Numpy) : 고차원 배열을 손쉽게 만들 수 있다.
import numpy as np
#넘파이 array() 함수에 리스트를 전달한다.
input_arr = np.array(fish_data)
target_arr = np.array(fish_target)
#배열에서 랜덤하게 샘플을 선택해 훈련 세트와 테스트 세트를 나눈다.
#무작위로 샘플 고르는 방식 -> 이때 두개의 배열에서 같은 위치는 함께 선택되어야 한다. 타깃이 샘플과 함께 이동해야 올바르게 훈련 가능
#인덱스 섞기
# arrange()에 정수 N을 전달하면 0~N-1까지 1씩 증가하는 배열을 만든다.
# random.shuffle() : 주어진 배열을 무작위로 섞는다.
np.random.seed(42)
index = np.arrange(49)
np.random.shuffle(index)
#print(index)
#전체 데이터를 훈련 세트와 테스트 세트로 나눈다.
train_input = input_arr[index[:35]]
train_target = target_arr[index[:35]]
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()
두번째 머신러닝 프로그램
- 훈련 세트와 테스트 세트로 k-최근접 이웃 모델 훈련
- fit() 메서드를 실행할 때마다 KNeighborsClassifier 클래스 객체는 이전에 학습한 것을 잃어버린다.
- 이전 모델을 그대로 두고 싶다면 KNeighborsClassifier 클래스 객체를 새로 만들어야 한다.
kn.fit(train_input, train_target)
kn.score(test_input, test_target)
# kn.predict(test_input)
#test_input #두개의 결과가 동일해야 한다.
02-2 데이터 전처리
전처리 과정을 거친 데이터로 훈련했을 때의 차이를 알고 표준점수로 특성의 스케일 변환하는 방법 배우기
문제점 : 새로운 데이터를 추가했을 때 예측이 잘못됨
넘파이로 데이터 준비하기
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을 채운 배열을 만든다.
#np.concatenate() : 첫번째 차원을 따라 배열 연결
fish_target = np.concatenate((np.ones(35), np.zeros(14)))
사이킷런으로 훈련 세트와 테스트 세트 나누기
문제점 : 일부 클래스의 수가 적으면 샘플이 골고루 섞이지 않을 수 있다. → saratify 매개변수 사용
from sklearn.model_selection import train_test_split
#train_test_split() : 전달되는 리스트나 배열을 비율에 맞게 훈련 세트와 테스트 세트로 나눠준다.
#random_state 매개변수 : 랜덤 시드 지정
#입력 데이터 2개, 타깃 데이터 2개
#기본적으로 25%를 테스트 세트로 떼어 낸다.
#입력 데이터 : 2차원 배열, 타깃 데이터 : 1차원 배열
#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)
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]])
삼각형 샘플에 가장 가까운 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()
print(train_input[indexes])
print(train_target[indexes])
삼각형과 가장 가까운 이웃에 도미가 하나밖에 포함되지 않았기 때문에 빙어로 예측
기준 낮추기
print(distances)
#[[ 92.00086956 130.48375378 130.73859415 138.32150953 138.39320793]]
- 삼각형 샘플에 가장 가까운 첫 번째 샘플까지의 거리 : 92
그 외 가장 가까운 샘플까지의 거리 : 130, 138 - x축은 범위가 좁고(10~40), y축은 범위가 넓다. (0~1000)
→ y축으로 조금만 벌어져도 거리가 아주 큰 값으로 계산되어 오른쪽 위의 도미 샘플이 이웃으로 선택되지 못한 것 - 두 특성(길이, 무게)의 값이 놓인 범위가 다르다 = 두 특성의 스케일(Scale)이 다르다.
- x축의 범위를 y축과 동일하게 맞춰본다.
#xlim() : x축 범위 지정, ylim() : 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()
데이터 전처리
- 표준 점수 (Standard Score) : 각 특성값이 평균에서 표준편차의 몇 배만큼 떨어져 있는지를 나타낸다.
- 분산 : 데이터에서 평균을 뺀 값을 모두 제곱한 다음 평균을 내어 구한다.
- 표준 편차 : 분산의 제곱근으로 데이터가 분산된 정도를 나타낸다.
#mean() : 평균 계산
#axis=0 : 행을 따라 각 열의 통계 값을 계삲나다.
mean = np.mean(train_input, axis=0)
#std() : 표준편차 계산
std = np.std(train_input, axis=0)
#각 특성마다 평균, 표준편차
print(mean, std)
#표준 점수로 변환 : 원본 데이터에서 평균을 빼고 표준편차로 나누기
#넘파이는 train_input의 모든 행에서 meand에 있는 두 평균 값을 빼준다. 그다음 std에 있는 두 표주편차를 다시 모든 행에 적용한다.
#브로드 캐스팅 (Braodcasting) : 크기가 다른 넘파이 배열에서 자동으로 사칙 연산을 모든 행이나 열로 확장하여 수행하는 기능
train_scaled = (train_input - mean) / std
전처리 데이터로 모델 훈련하기
#train_scaled : 표준점수로 변환한 데이터
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()
모양은 이전과 동일하지만 x축과 y축의 범위가 비슷해짐
#다시 k-취근접 이웃 모델 훈련
#테스트 세트도 훈련 세트의 평균과 표준편차로 변환해야 한다.
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()
이제 샘플에서 가장 가까운 샘플은 도미가 된다.
'Study > PBL' 카테고리의 다른 글
[혼공머신] Ch04 (0) | 2024.07.18 |
---|---|
[혼공머신] Ch03 (0) | 2024.07.17 |
딥러닝 모델 경량화 (0) | 2024.07.11 |
Deep Fake voice recognition (0) | 2024.07.11 |
Machine Learning 3 (0) | 2024.05.28 |