로지스틱 회귀(Logistic Regression) 다중분류

이전까지는 age, weight, oxygen, runtime, runpulse, rstpulse 데이터를 통해서 maxpulse를 예측하는 예제를 살펴봤습니다. maxpulse는 연속된 값을 가지고 있는 수치-연속형 데이터입니다.

dataset = pd.read_csv('./fitness.csv')
dataset.head()

데이터의 특징은 아래와 같습니다.

dataset.info()

RangeIndex: 31 entries, 0 to 30
Data columns (total 7 columns):
# Column Non-Null Count Dtype
— —— ————– —–
0 age 31 non-null int64
1 weight 31 non-null float64
2 oxygen 31 non-null float64
3 runtime 31 non-null float64
4 runpulse 31 non-null int64
5 rstpulse 31 non-null int64
6 maxpulse 31 non-null int64
dtypes: float64(3), int64(4)
memory usage: 1.8 KB

앞으로 하려고 하는 부분은 weight, oxygen, runtime, runpulse, rstpulse, maxpulse 칼럼 정보를 통해서 이 사람이 어느 나이대인가를 예측하는 분류의 문제를 해결해보도록 하겠습니다.

그러나 아쉽게도 예제 데이터는 범주형 컬럼은 없고 모두 수치형-연속형 데이터들입니다. 그렇기 때문에 범주형-순서형 데이터 컬럼을 하나 만들어줘야합니다. 아래와 같은 범주형 데이터 컬럼을 하나 만들겠습니다.
나이가 40대 이하이면 1, 40~50 사이에 있으면 2, 50~60 사이에 있으면 3 이렇게 넣어보겠습니다.

범주형 : 몇개의 범주로 나눠진 자료로 명목형, 순서형 데이터가 있음
* 명목형 : 성별, 성공여부, 혈액형 등 단순히 분류된 자료
* 순서형 : 개개의 값들이 이산적이며 그들 사이에 순서 관계가 존재하는 자료

수치형 : 이산형과 연속형으로 이뤄진 자료로 이산형과 연속적인 형태의 자료가 있음
* 이산형 : 이산적인 값을 갖는 데이터로 출산 횟수 등을 의미
* 연속형 : 연속적인 값을 갖는 데이터로 키나 몸무게 등을 의미

dataset.loc[ dataset['age'] < 40, 'ACODE']= 1
dataset.loc[ (dataset['age'] >= 40) & (dataset['age'] <50), 'ACODE']= 2
dataset.loc[ (dataset['age'] >= 50) & (dataset['age'] <60), 'ACODE']= 3

훈련에 사용하는 컬럼은 나이를 제외한 나머지 컬럼들입니다. 어떤 내용들이 있는지 살펴보면 아래와 같습니다.

해당 데이터를 3차원 평면에 나타내보면 아래와 같습니다. 그래프를 보면 3개의 포인터가 다른 색으로 분류되어 있습니다. 데이터가 많지 않고 5차원 데이터를 3차원으로 축소한 형태이기 때문에 각 분류가 정확하지 않은것 같습니다. 학습 데이터가 좋은 형태로 되어 있다면 아마도 그래프의 각 요소들이 잘 구분되어 있을테지만 아쉽게도 예제 데이터는 그렇지 않은듯합니다.

from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(1, figsize=(8, 6))
ax = Axes3D(fig, elev=-150, azim=110)
X_reduced = PCA(n_components=3).fit_transform(dataset[dataset.columns[:-1]])
ax.scatter(X_reduced[:, 0], X_reduced[:, 1], X_reduced[:, 2], c=y,
           cmap=plt.cm.Set1, edgecolor='k', s=40)
ax.set_title("First three PCA directions")
ax.set_xlabel("1st eigenvector")
ax.w_xaxis.set_ticklabels([])
ax.set_ylabel("2nd eigenvector")
ax.w_yaxis.set_ticklabels([])
ax.set_zlabel("3rd eigenvector")
ax.w_zaxis.set_ticklabels([])

plt.show()

이제 sklearn 패키지의 분류문제를 풀수 있는 LogisticRegression를 사용해보겠습니다. 사용하는 방법은 LinearRegression과 같이 간단하게 사용할 수 있습니다. x 데이터와 y 데이터는 위에서 설명해드린 데이터를 사용합니다.

그런다음 LogisticRegression에서 옵션을 선택하고 해당 모델을 학습합니다. sklearn은 효율적인 학습을 위해 몇가지 효율적인 학습 알고리즘을 제시합니다. 특히 feature의 수, 학습 데이터의 양, 분류할 문제의 수 등을 따라서 필요한 알고리즘을 선택합니다.

이번 예제는 3개의 분류 문제(multiclass problems)를 풀어야 하기 때문에 ‘newton-cg’ 알고리즘을 사용하도록 하겠습니다. 이 외에도 여러 알고리즘과 파라메터가 있습니다. sklearn 공식 사이트에서 해당 내용들을 확이해보시기 바랍니다.

https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html
x = dataset[dataset.columns[1:-1]].values
y = dataset['ACODE'].values

from sklearn.linear_model import LogisticRegression
clf = LogisticRegression(solver='newton-cg', max_iter=100).fit(x, y)

predict = clf.predict(x)
accuracy=(predict.reshape(-1,1) == y.reshape(-1,1)).sum()/len(y)
print(accuracy)
# 0.8387096774193549 정확도

알고리즘을 통해 확인해보니 0.8387 의 정확도를 보여줍니다. 학습용 데이터가 작기 때문에 테스트용 데이터를 만들 수 없었던 이유로 정확도 계산을 한다고 하기도 좀 애매하지만 더 많은 데이터를 통해서 훈련과 테스트를 해보시길 권해드립니다.

그리고 학습이 완료된 후에 기울기와 절편 정보를 출력해보면 아래와 같습니다.

print('W:{}, b:{}'.format(clf.coef_.T, clf.intercept_.T))
W:[[ 0.46533128 -0.20477993 -0.26055162]
 [ 0.60397447 -0.08600717 -0.5179662 ]
 [-0.13946355  0.42710757 -0.28764394]
 [ 0.21778426 -0.00474545 -0.2130358 ]
 [ 0.00648806  0.03361824 -0.04010692]
 [ 0.05094977 -0.07150677  0.02055985]], b:[-116.45602409   30.69276337   85.76326072]

그리고 이러한 데이터를 통해서 직접 행렬곱을 해봐도 같은 결과가 나오는 것을 확인할 수 있습니다.

y_hat = np.matmul(x,clf.coef_.T)+clf.intercept_
y_hat.argmax(axis=1)+1

최근접이웃 알고리즘(K-NN)

k-NN(Nearest Neighbors) 알고리즘은 가장 간단한 머신러닝 알고리즘입니다. 훈련용 데이터셋을 통해서 모델을 만들고 새로운 데이터가 입력될 때는 훈련 데이터셋에서 가장 가까운 “최근접 이웃”을 찾습니다.

KNN 알고리즘의 좋은 설명을 해주는 사이트의 허민석님의 강의를 올려드리니 참고해보시면 좋겠습니다. 이 외에도 알고리즘을 설명하는 많은 강의 사이트가 있으니 개념이 궁금하신 분들은 찾아보시길 추천해드립니다.

이번 글에서는 개념에 대한 설명보다는 바로 예제 코드를 살펴보도록 하겠습니다. 해당 알고리즘은 sklearn에서 이미 잘 구현했기 때문에 사용자가 별도의 알고리즘을 구현한 필요가 없습니다. 사용자는 단 몇줄의 코드만으로 해당 알고리즘을 사용할 수 있습니다. 예제는 sklearn에서 제공하는 KNeighborsClassifier를 사용하도록 하겠습니다. 사용하는 데이터 역시 sklearn에서 제공하는 load_iris() 데이터를 사용해보겠습니다.

Introduction to Machine Learning with Python, KNeighborsClassifier

sklearn에서 제공하는 다양한 데이터셋이 있습니다. 그중에 이번 예제는 붗꽃 데이터를 사용해보겠습니다. 붗꽃 데이터는 꽃받침과 꽃잎의 넓이와 길이 정보와 붗꽃의 종류(setosa, versicolor, virginica) 데이터의 형식으로 되어 있습니다. 4개의 feature 정보와 label 컬럼이 있고 데이터의 수는 150개 정도이기 때문에 분류 문제를 테스트해보기에 적절한 예제입니다.

from sklearn.datasets import load_iris
iris = load_iris()
iris.keys()
#dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])

feature 정보는 아래와 같이 sepal(꽃받침) length, sepal width, petal(꽃잎) length, petal width의 네개 컬럼 정보가 들어있습니다.

iris.feature_names
#['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

해당 데이터를 pandas의 데이터프레임으로 데이터 타입을 바꾸면 좀 더 편하게 데이터의 내용을 확인 할 수 있고 pandas에서 제공하는 다양한 함수를 사용할 수 있습니다.

import pandas as pd
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df.head()
df.describe()

sklearn의 KNeighborsClassifier 패키지를 임포트합니다. 그리고 데이터를 훈령용 세트와 테스트용 세트를 8:2로 분리해서 x_train, y_train, x_test, y_test 형태로 데이터를 생성합니다. 데이터 세트를 분리한 후에 shape을 보면 120:30의 형태로 데이터가 나뉜 것을 확인할 수 있습니다.

from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, shuffle=False, random_state=701)
print(x_train.shape, x_test.shape)
#(120, 4) (30, 4)

n_neighbors의 적절한 이웃 값을 찾기 위해서 데이터 셋을 테스트해봅니다. 이웃 값을 너무 적게 하면 모델의 복잡도가 올라가고 너무 많게 하면 모델의 예측력이 떨어지기 때문에 적절한 값을 찾는 것이 중요합니다.

train_accuracy = []
test_accuracy = []
neighbors_set = range(1,11)
for n_neighbors in neighbors_set:    
    clf = KNeighborsClassifier(n_neighbors=n_neighbors)
    clf.fit(x_train, y_train)
    score = clf.score(x_test, y_test)
    train_accuracy.append(clf.score(x_train, y_train))
    test_accuracy.append(clf.score(x_test, y_test))
import matplotlib.pyplot as plt

plt.plot(neighbors_set, train_accuracy, label='train')
plt.plot(neighbors_set, test_accuracy, label='test')
plt.legend()

위의 결과 값과 같이 이웃 값(n_neighbors)이 5일 경우에 가장 높은 예측 정확도를 보여줍니다. 모델을 생성한 후 예측의 정확도를 보기 위해 테스트 데이터를 사용해서 예측을 수행하고 이 값을 테스트 값과 비교해본 결과 80%의 예측 정확도를 얻었습니다.

clf = KNeighborsClassifier(n_neighbors=5)
clf.fit(x_train, y_train)
clf.predict(x_test)
# array([2, 2, 2, 1, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1])
(clf.predict(x_test) == y_test).sum()/len(y_test) # 0.8

다만 이 알고리즘을 사용할 경우 이웃을 어떻게 적절히 정의할 것인가에 대한 고민이 필요합니다. 만약 이웃을 적게 사용한다면 모델의 복잡도가 높아지고 많이 사용하면 복잡도는 낮아집니다. 위의 이미지에서 가장 오른쪽에 이미지의 경계면이 가장 부드럽지만 이렇게되면 모델이 지나치게 일반화 되어서 예측하는 값의 정확도가 낮아질 염려가 있습니다.

k-NN 알고리즘의 특징은 이해하기 매우 쉬운 모델이라는 점입니다. 사용이 비교적 간단하지 좋은 성능을 발휘하기 때문에 어떤 높은 난이도의 문제를 해결하기 전에 시도해봄직한 모델이라고 할 수 있습니다. 그러나 쉬운 모델이지만 훈련용 세트가 커지만 예측이 느려지는 특징이 있기 때문에 널리 사용되진 않습니다.

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class ANN(nn.Module):
    
    def __init__(self, D_in, H, D_out):
        super().__init__()
        self.layers = nn.Sequential(
            nn.Linear(D_in, H),
            nn.ReLU(),
            nn.Linear(H, D_out),
        )
    
    def forward(self, x):
        x = x.float()
        return self.layers(x)

# input dim, hidden size, ont-hot
model = ANN(tx_train.size(dim=1),5,torch.unique(ty_train).size(dim=0))
model

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters())

nb_epochs = 5001
for epoch in range(nb_epochs):
    model.train()
    predict = model(tx_train)
    loss = criterion(predict, ty_train.squeeze().long())
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    if epoch % 250 == 0:
        print('{}/{}, cost:{:.5f}'.format(epoch,nb_epochs,loss.item()))

참고로 위의 코드는 pytorch를 사용해서 동일한 예측 코드를 Linear Regression으로 구현한 것입니다.

sklearn.datasets

Load_Boston 데이터셋

sklearn에서는 간단한 머신러닝 알고리즘 분석과 테스트를 위해서 작은 규모의 데이터셋(small toy datasets)을 datasets이라는 패키지에 담아두었습니다. 해당 데이터셋들은 데이터에 대한 정보와 특징들이 포함되어 있어 데이터셋을 이용하는 사용자로 하여금 해당 데이터셋이 어떤 의미인가를 쉽게 이해할 수 있도록 해주고 있습니다.

https://scikit-learn.org/stable/datasets/index.html#toy-datasets

공식 홈페이지에 들어가보시면 제공하는 데이터의 내용들을 확인 하실 수 있습니다. 간략한 정보는 아래와 같습니다.

  • load_boston : 보스턴 지역의 집값 데이터(회귀분석)
  • load_iris : 붗꽃 데이터(분류)
  • load_diabetes : 당뇨병 데이터(회귀분석)
  • load_digits : 숫자 이미지 데이터(분류)
  • load_linnerud : 20대 중반 남성의 신체정보와 운동정보(다변량분석)
  • load_wine : 와인의 특징에 따른 종류(분류)
  • load_breast_cancer : 유방암 데이터(분류)
from sklearn.datasets import load_boston
boston = load_boston()

데이터셋을 로딩하는데는 load라는 명령어와 함께 해당 데이터셋의 이름을 적어주면 간단히 로딩할 수 있습니다.
데이터를 로딩한 후에는 DESCR 을 통해서 해당 데이터셋이 어떤 특징이 있는지 살펴볼 수 있습니다.

print(boston.DESCR)
.. _boston_dataset:

Boston house prices dataset
---------------------------

**Data Set Characteristics:**  

    :Number of Instances: 506 

    :Number of Attributes: 13 numeric/categorical predictive. Median Value (attribute 14) is usually the target.

    :Attribute Information (in order):
        - CRIM     per capita crime rate by town
        - ZN       proportion of residential land zoned for lots over 25,000 sq.ft.
        - INDUS    proportion of non-retail business acres per town
        - CHAS     Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)
        - NOX      nitric oxides concentration (parts per 10 million)
        - RM       average number of rooms per dwelling
        - AGE      proportion of owner-occupied units built prior to 1940
        - DIS      weighted distances to five Boston employment centres
        - RAD      index of accessibility to radial highways
        - TAX      full-value property-tax rate per $10,000
        - PTRATIO  pupil-teacher ratio by town
        - B        1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
        - LSTAT    % lower status of the population
        - MEDV     Median value of owner-occupied homes in $1000's

    :Missing Attribute Values: None

    :Creator: Harrison, D. and Rubinfeld, D.L.

This is a copy of UCI ML housing dataset.
https://archive.ics.uci.edu/ml/machine-learning-databases/housing/
...

DESCR 외에도 해당 boston 데이터셋에는 몇가지의 key 값이 더 있습니다. 해당 키값을 모두 보기 위해서는 boston.key() 명령을 사용합니다.

boston.keys()
# dict_keys(['data', 'target', 'feature_names', 'DESCR', 'filename'])
  • data : 데이터셋의 정보가 numpy.ndarray 형태로 저장
  • target : 레이블 정보
  • feature_names : 데이터셋의 컬럼정보
  • DESCR : 데이터셋 설명
  • filename : 해당 데이터셋의 저장 위치 정보 표시

이렇게 입력된 데이터는 컬럼 정보와 분리되어 있기 때문에 보기에 좀 불편하고 어려울 수 있습니다. 이럴 때에 pandas 패키지를 통해 데이터프레임을 만들면 탐색적데이터분석에 좀 더 유리합니다.

import pandas as pd
df = pd.DataFrame(data=boston.data, columns = boston.feature_names)
df['TARGET'] = boston.target
df.head()

pandas의 데이터프레임으로 해당 데이터를 변경해보면 위와 같은 형태로 보여지기 때문에 데이터를 보기가 좀 더 편리합니다. 좀 더 자세한 정보를 보시고 싶으시면 df.info(), df.describe()와 같은 함수를 사용해보시면 각 컬럼의 데이터 타입과 기본적인 통계정보를 확인 할 수 있습니다. 추가로 matplotlib과 같은 시각화 함수를 사용하면 데이터를 내용을 더 쉽게 파악할 수 있습니다.

import matplotlib.pyplot as plt
plt.figure(figsize=(12,5))
plt.scatter(scaled_df['AGE'],scaled_df['DIS'])
corr = scaled_df.corr()
corr.style.background_gradient(cmap='coolwarm')

시각화로 데이터셋의 내용을 살펴본 후에 학습을 위해서 데이터를 나눠줄 필요가 있을 경우에 sklearn은 훌륭한 유틸 함수를 제공합니다. 아래와 같이 model_selection 패키지에서 train_test_split을 사용해서 학습용, 훈련용 데이터셋을 만들 수 있습니다.

from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(boston.data, boston.target, test_size=0.2, shuffle=False, random_state=701)
print(x_train.shape) #404,13
print(x_test.shape) #102,13

Load_Digit 데이터셋

boston 데이터셋은 연속된 값을 가지는 회귀분석에서 많이 사용하는 예제입니다. 이번에는 분류 문제에 사용하는 데이터셋인 숫자(digit) 데이터셋을 살펴보겠습니다. 이 데이터의 shape은 (1797, 64) 입니다. 이것은 8 x 8 이미지를 1차원(64)으로 생성한 값인데 이러한 이미지가 1,797개가 있다는 의미입니다.

from sklearn.datasets import load_digits
digits = load_digits()
digits.data[0]
array([ 0.,  0.,  5., 13.,  9.,  1.,  0.,  0.,  0.,  0., 13., 15., 10.,
       15.,  5.,  0.,  0.,  3., 15.,  2.,  0., 11.,  8.,  0.,  0.,  4.,
       12.,  0.,  0.,  8.,  8.,  0.,  0.,  5.,  8.,  0.,  0.,  9.,  8.,
        0.,  0.,  4., 11.,  0.,  1., 12.,  7.,  0.,  0.,  2., 14.,  5.,
       10., 12.,  0.,  0.,  0.,  0.,  6., 13., 10.,  0.,  0.,  0.])
plt.imshow(digits.data[0].reshape(8,8))

해당 배열의 첫번째 값을 가지고 8×8배열로 만든 후에 이것을 이미지로 표시해보면 위와 같은 이미지 “0” 값이 나옵니다. 즉 이런 데이터가 1,797개가 있다는 의미입니다. 이러한 데이터를 훈련시키면 숫자가 입력될 때 이것이 어떤 숫자인지 예측할 수 있게 됩니다.

from sklearn.decomposition import PCA
pca = PCA(n_components=2) # 시각화를 위해 2차원으로 성분을 추출
dim2data = pca.fit_transform(digits.data)
plt.figure(figsize=(6,6))
plt.scatter(dim2digit[:,0], dim2digit[:, 1], c=digits.target, linewidth=1)
plt.show()

지도학습(Supervised Learning)

정의

지도학습은 가장 널리 사용되는 머신러닝 방법 중에 하나입니다. 지도학습의 특징은 입력(Input)과 출력 데이터(Label)가 존재한다는 것이죠. 기존에 존재하는 Input/Label 데이터 들을 통해서 어떤 알고리즘을 만들고 새로운 데이터가 들어왔을 때에 만들어진 알고리즘에 기반하여 출력값을 내는 것을 의미합니다.

말이 좀 복잡하지만 쉽게 말해서 지도학습이란 그 말 자체에서 처럼 “학습자(여기서는 컴퓨터와 같은 Machine)에게 데이터의 특징과 이에 대한 정확한 답변을 주고 그 특징을 학습시킨 후에 새로운 데이터를 주었을때 학습의 결과로 어떤 결과값을 예측하는 것”이라고 할 수 있겠습니다.

반대의 경우를 비지도학습(Unsupervised Learning)이라고 하는데 이런 경우는 학습자에게 데이터 외에는 아무것도 알려주지 않고 스스로 학습하는 과정을 통해 새로운 데이터가 주어졌을때 결과값을 예측하는 것입니다.

지도학습의 종류

지도학습의 종류는 크게 분류(Classification) 문제와 회귀(Regression) 문제가 있습니다. 간단히 말하면 분류는 입력 데이터가 있을 경우 미리 정의된, 가능성 있는 여러 클래스 레이블 중에 어디에 들어가는가를 예측하는 하는 것입니다. 둘 중에서 어느 그룹에 속하는 것인가를 다르는 것을 이진 분류(Binary Classification)이라고 하고 둘 이상의 그룹 중에서 어디에 들어가는 것인가를 예측하는 것이 다중 분류(Multiclass Classification)이라고 합니다.

실제로 이 분류의 문제는 상당히 많은 곳에서 사용되고 있습니다.

이진분류는 “예/아니오”의 문제를 푸는 것이라고 할 수 있겠습니다. 이 분류는 많은 부분에서 사용되고 있습니다. 이메일에서 스팸을 분류 한다거나, 신용카드 회사에서 이것이 정상적인 거래인가 비정상적인 거래인가를 예측하는 것도 이런 이진 분류의 문제입니다.

반면에 다중 분류의 경우로 가장 많이 알려진 예제는 바로 붗꽃 데이터 예제입니다. 앞으로 다뤄볼 예제이기도 합니다. 해당 데이터는 꽃 받침과 꽃 잎의 길이와 넓이 정보로 해당 붗꽃이 setosa / versicolor / virginica 세개의 품종 중에 어디에 속하는가를 예측하는 분류입니다.
이 외에도 와인의 산도나 당도를 통해서 와인의 종류를 예측하는 문제도 있습니다. 이 외에도 분류의 문제는 다양한 곳에 적용됩니다. 이미지를 통해서 개와 고양이를 분류한다던가 고객이 물건을 구입하거나 하지 않거나를 예측하기도 합니다.

반면 회귀는 연속적인 숫자를 예측하는 것입니다. 몇가지 특징을 통해서 어떤 값을 예측하는 경우를 예측해보면 우리 일상에도 다양한 분야에 적용할 수 있습니다.

예를 들어서 방의 갯수, 면적 등을 통해서 집값을 예측한다거나 교육의 수준, 나이, 주거지 등을 통해서 연간 소득을 예측한다거나 하는 것도 회귀 분석의 예입니다. 이 밖에도 농장에서 전년도 수확량, 날씨, 고용 인원을 통해서 수확량을 예측해보는 것도 회귀 분석의 예입니다.

이 두분석의 가장 큰 차이는 예측값이 정성적 자료 형태 즉, 범주와 순서의 형태인가 아니면 정량적 자료 형태 즉, 어떤 연속적인 수치형태를 가지는가를 생각해보면 쉽게 구분할 수 있습니다.

실제로 어떤 문제를 해결할 때에 “이것을 분류의 문제인가 혹은 회귀의 문제인가”에 대한 정의를 하지 못해서 잘못된 알고리즘을 적용하는 경우가 종종 있습니다.

만약 내가 연소득, 수확량 등의 값을 예측한다면 회귀의 문제입니다. 반면 어떤 직군, 어떤 종류에 속하는가를 예측하는 것은 분류의 문제입니다.

일반화, 과대적합, 과소적합

지도학습이 잘 이뤄진 경우는 훈련 데이터를 통해서 그 데이터셋의 특징을 정확히 파악해서 모델을 만들고 새로운 데이터가 들어왔을 때에 모델을 통해서 정확도가 높은 예측값을 출력해 낼 수 있습니다. 이런 것을 일반화(Generalization)이라고 합니다.

그러나 훈련용 데이터 셋이 너무 복잡하거나 너무 빈약한 경우에 모델이 일반화 되지 않고 단지 훈련용 데이터만 잘 반영하는 일이 발생하기도 합니다. 이런 경우에는 훈련용 데이터로는 정확한 예측을 해내지만 새로운 데이터가 들어왔을 경우에는 정확도가 낮은 값을 예측하게 됩니다. 이런 경우를 모델이 과대적합(Overfitting)되어 있다라고 이야기합니다.

반대로 모델이 너무 간단하면 이러한 모델을 통해서는 지나치게 대략적인 정보만 얻을 수 밖에 없기 때문에 이를 통한 예측 역시 어떤 의미를 찾기 어려울 수도 있습니다. 이런 경우는 과소적합(Underfitting)되어 있다라고 합니다.

다시 말하면 모델을 훈련을 많이 할 수록 예측도는 높아집니다. 그러면서 일반화는 높아지게 됩니다. 그러나 너무 훈련을 많이하게되면 모델이 데이터셋에 지나치게 민감해저 과대적합이 일어나게 됩니다. 그렇다고 모델을 훈련을 적게 한다면 과소적합이 일어납니다. 머신러닝을 통해서 훈련하게 되면 이런 일반화 곡선이 최대가 되는 점을 찾아야 합니다.