[혼자 공부하는 머신러닝] 1. 나의 첫 머신러닝 & 2. 데이터 다루기
인공지능이란?
인공지능은 사람처럼 학습하고 추론할 수 있는 지능을 가진 컴퓨터 시스템을 만드는 기술이다.
지금 우리가 사용하는 인공지능의 기본인 뉴런과 퍼셉트론과 같은 개념은 1900년대 중반에 나왔지만 컴퓨터 성능의 한계로 진정한 지능의 영역에 도달하지 못하여 AI겨울을 맞이하게 되었다.
머신러닝이란?
머신러닝은 규칙을 일일이 프로그래밍 하지 않고 자동으로 데이터에서 규칙을 학습하는 알고리즘을 연구하는 분야이다.
즉, 인공지능의 하위 분야 중에서 지능을 구현하기 위한 소프트웨어를 담당하는 분야이다.
딥러닝이란?
머신러닝의 알고리즘 중에서 인공 신경망을 기반으로 한 방법들을 통칭하여 딥러닝 이라고 부른다.
AI겨울을 이겨내기 위해 인공지능에 대한 연구를 지속하다 신경망 모델을 만들어 이미지를 인식하는 데 성공을 하여 다시 인공지능의 부흥을 이끌었다.
실제 데이터 분류 하기
머신러닝은 여러 개의 데이터를 분석하여 원소들을 분류할 기준을 찾는다.
따라서 기준을 정하기 위해 많은 데이터를 학습해야 한다.
도미의 경우 도미의 길이와 무게와같은 각각의 데이터를 구분할 수 있는 특징이 있는데 이를 특성(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]
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]
도미의 데이터가 위와 같이 있다고 했을 때 데이터를 그래프로 표현하면 시각적으로 보여 이해하기 쉽고 그중에서 산점도를 사용하면 데이터들의 각각의 특성에 따른 분포를 확인할 수 있다.
import matplotlib.pyplot as plt
plt.scatter(bream_length, bream_weight) # 산점도
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
그리고 동일한 방법으로 도미 데이터와 구분되는 빙어 데이터를 사용하여 산점도로 도미 데이터와 같이 표현하면 아래와 같은 산점도가 나온다.
matplotlib에서는 산점도가 2개일 경우 색깔로 구분해서 파란색이 도미 데이터의 분포이고 주황색이 빙어 데이터의 분포이다.
K-NN 알고리즘
특정 데이터를 분류할 때 주위의 다른 데이터를 보고 다수를 차지하는 것을 정답으로 사용하는 방식이다.
즉, 새로운 데이터가 들어오면 가지고 있는 모든 데이터와 비교하여 직선 거리가 가장 가까운 데이터를 파악하여 다수를 차지하고 있는 군집으로 분류한다.
다만 이러한 방식에서 알 수 있듯이 모든 데이터를 비교하기 때문에 데이터의 크기가 큰 경우 시간이 매우 오래걸리고, 특성의 수가 많은 경우도 직선 거리를 계산하는데 많은 시간이 걸리기 때문에 다른 방식을 사용하는 것이 더 좋다.
K-NN을 활용하여 위의 생선 데이터에 새로운 샘플을 분류하는 상황을 보면 만약 새로운 샘플을 아래와 같이 산점도에 추가하였다고 한다면 직관적으로 새로운 데이터가 도미일 것으로 추정할 수 있다.
이를 sklearn의 KNeighborsClassifier을 사용하여 분류를 해보면 아래의 코드 실행 결과 새로운 데이터가 cluster 1번 즉 도미로 분류 되는 것을 확인 할 수 있다.
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
kn.fit(fish_data, fish_target)
kn.score(fish_data, fish_target)
kn.predict([[30, 600]]) # 결과: 도미로 분류
KNeighborsClassifier에서 기본적으로 참고하는 근접 데이터의 수는 5개인데 n_neighbors의 수를 변경하면 임의로 참고하는 데이터의 수를 변경할 수 있다.
이때 n_neighbors수를 너무 작게 하면 노이즈에 너무 민감하게 반응하여 잘못 분류할 수 있고, 너무 크게 하면 직선거리가 매우 먼 데이터가 영향을 미칠 수 있으므로 적절한 값을 선택하는 것이 중요하다.
# 참고하는 근접 데이터 수 변경
kn49 = KNeighborsClassifier(n_neighbors=49)
kn49.fit(fish_data, fish_target)
kn49.score(fish_data, fish_target)
kn49.predict([[12, 15]]) # 결과: 도미로 분류
만약 위 처럼 모든 데이터를 사용하여 K-NN알고리즘을 적용하면 도미의 데이터 수가 많기 때문에 어떤 새로운 데이터가 들어와도 근접한 데이터중 가장 많은 것은 도미가 나오게 된다.
따라서 위에 빙어로 추정되는 데이터가 들어왔음에도 도미로 분류되는 오류가 발생한다.
지도 학습과 비지도 학습
- 지도학습
훈련 데이터에 레이블이라는 원하는 답이 포함되어 있다.
대표적으로 분류(classification), 예측 변수(predictor variable)를 통해 target 의 수치를 예측하는 회귀 (regression)가 있다. - 비지도 학습
훈련 데이터에 레이블이 없는 데이터를 통해 학습하는 것이다.
대표적으로 군집(clustering), 시각화와 차원축소(visualization & dimensionality reduce), 연관 규칙 학습(association rule learning)이 있다.
훈련 세트와 테스트 세트
- 훈련 세트
모델을 훈련할 때 사용하는 데이터로 훈련 세트가 크면 클수록 더 정확한 예측이 가능하다. - 테스트 세트
모델을 평가할 때 사용하는 데이터 세트로 전체 데이터 세트에서 20~30% 정도를 테스트 세트로 사용한다.
다만 전체 데이터 세트가 매우 큰 경우 테스트 세트의 비율이 작아도 상관 없다. - 샘플링 편향
훈련 세트와 테스트 세트에 샘플이 골고루 섞여있지 않고 샘플링이 한쪽으로 치우친 경우이다.
데이터 세트를 훈련 세트와 테스트 세트로 나눌 때 데이터가 많은 경우에는 확률적으로 골고루 나눠질 확률이 높기 때문에 순수하게 무작위로 나누는 방법을 사용하여도 크게 문제가 없다.
하지만 데이터의 수가 적을 경우 샘플링 편향이 생길 수 있다.
즉, 샘플링을 할 때 중요한 특징들은 전체 데이터의 비율에 맞게 추출해서 샘플의 편향을 줄여야 한다.
데이터 세트를 테스트 세트와 훈련 세트로 분할 할 때 sklearn의 train_test_split을 이용하면 쉽게 분리할 수 있다.
이때 무작위로 추출하게 된다면 샘플링 편향이 발생할 수 있기 때문에 stratify 매겨변수에 타깃 데이터를 전달하여 클래스 비율에 맞게 데이터를 나눌 수 있다
import numpy as np
from sklearn.model_selection import train_test_split
import collections
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, stratify=fish_target, random_state=42)
collections.Counter(test_target) # {0.0: 4, 1.0: 9}
대략 1 : 2.25의 비율로 14 : 35(1 : 2.5)의 비율과 유사하게 추출되었다.
데이터 스케일링
위의 물고기 데이터 세트에 세로운 데이터로 길이가 25이고 무게가 150인 데이터가 들어온다면 이를 산점도로 나타내면 아래와 같다.
이는 그래프 상으로는 도미로 분류되는 것이 적절한 것으로 보이지만 막상 K-NN알고리즘으로 분류하면 cluster0인 빙어로 분류가 된다.
이를 알아보기 위해 근접한 값들을 따로 표시해주면 아래와 같이 표현이 된다.
이러한 문제가 발생한 이유는 x축과 y축의 범위가 달라서 발생하는 문제로 현재 x축의 경우 길이가 10에서부터 40까지 이지만 y축의 경우 무게가 0에서부터 1000까지로 차이가 크다.
따라서 특성의 값이 놓인 범위가 다른 부분을 일정한 기준으로 맞춰주는 데이터 전처리 과정을 거쳐야 한다.
전처리 방법 중에서 가장 널리 사용되는 방법은 표준점수로 특성값이 0에서 표준편차의 몇 배만큼 떨어져 있는지를 나타낸다.
표준점수 공식: $z = \frac {x - \mu}{\sigma} \quad x: 원수치, \mu : 평균, \sigma : 표준편차$
이를 이용해서 물고기 데이터를 전처리를 다음과 같이 할 수 있다.
mean = np.mean(train_input, axis=0)
std = np.std(train_input, axis=0)
train_scaled = (train_input - mean) / std
new = ([25, 150] - mean) / std
전처리를 한 다음 근접한 데이터를 보면 위처럼 도미쪽과 근접해 있다는 것을 볼 수 있고 새로운 데이터가 K-NN알고리즘에 의해서 도미로 잘 분류되는 것을 볼 수 있다.