머신러닝 기초 (2) - Supervised Learning: Regression and Classification
Supervised Learning의 두 축인 Regression과 Classification을 배우는 2편입니다.
머신러닝 기초 시리즈의 2편입니다. 1편의 전체 지도에 이어, Supervised Learning의 개념부터 시작합니다.
Supervised Learning이 하는 일
Supervised learning(지도학습) 은 정답이 있는 데이터로 배우는 학습 방식입니다. 데이터는 (feature, target) 쌍의 모음입니다. feature는 모델에 주는 입력이고, target은 그 입력에 대응하는 정답입니다.
데이터셋을 수식으로 적으면 다음과 같습니다. sample이 \(n\)개이고 feature가 \(d\)개라면,
\[s D = {(\mathbf{x}i, y_i)}{i=1}^{n}, \quad \mathbf{x}_i \in \mathbb{R}^d\]즉 feature 벡터 \(\mathbf{x}_i\)와 target \(y_i\)의 쌍 \(n\)개입니다.
여기서 \(\mathbf{x}_i \in \mathbb{R}^d\)는 “\(\mathbf{x}_i\)는 실수 \(d\)개를 묶은 vector”라는 뜻입니다. 집값 예제라면 면적, 방 개수, 위치 점수를 묶은 \(\mathbf{x}_i = (85.0,\, 3,\, 7.2)\) 같은 벡터가 입력 하나이고, 거기에 붙은 매매가가 \(y_i\)입니다.
목표는 특성에서 타깃으로 가는 함수를 찾는 것입니다. 지도학습은 데이터 \(D\)로부터 다음 함수를 근사하는 문제입니다.
\[f: \mathcal{X} \to \mathcal{Y}, \qquad \hat{y} = f(\mathbf{x})\]위 식에서 \(\mathcal{X}\)는 입력이 사는 공간(여기서는 \(\mathbb{R}^d\)), \(\mathcal{Y}\)는 타깃이 사는 공간입니다. 모자를 씌운 \(\hat{y}\)(“와이 햇”이라 읽습니다)는 모델의 예측값입니다. 실제값 \(y\)와 구분하려고 예측에는 항상 모자를 씌우며, 이 표기는 시리즈 내내 쓰입니다. “지도(supervised)”라는 말은 학습 과정에서 정답 \(y\)가 곁에 있어, 모델이 자기 예측 \(\hat{y}\)가 맞았는지 틀렸는지 알 수 있다는 뜻입니다.
한 가지 더 짚을 것이 있습니다. 현실 데이터에서는 같은 입력이 항상 같은 정답으로 이어지지 않습니다. 면적과 방 개수가 똑같은 두 집이 서로 다른 값에 팔립니다. 그래서 데이터가 다음처럼 생성되었다고 보는 것이 정직한 모형입니다.
\[y = f^{*}(\mathbf{x}) + \varepsilon\]여기서 \(f^{*}\)는 우리가 모르는 진짜 관계이고, \(\varepsilon\)(입실론)은 측정 오차와 관측하지 못한 요인들이 만드는 노이즈입니다. 지도학습은 유한한 데이터 \(D\)만 보고 \(f^{*}\)에 최대한 가까운 \(f\)를 고르는 일입니다. 노이즈 \(\varepsilon\)까지 맞힐 수는 없으므로, 완벽한 예측은 애초에 목표가 아닙니다. 이 사실은 뒤의 회귀 실습에서 다시 확인합니다.
정답 \(y\)가 없는 데이터에서 구조 자체를 찾는 것은 비지도학습(unsupervised learning)이며, 이 시리즈의 15편부터 다룹니다.
회귀와 분류
타깃이 사는 공간 \(\mathcal{Y}\)의 구조에 따라 지도학습은 둘로 갈립니다. 타깃이 연속값이면 회귀, 범주면 분류입니다.
- 회귀(regression): 타깃이 숫자입니다. \(y \in \mathbb{R}\), 즉 \(\mathcal{Y}\)가 실수 전체(또는 그 구간)입니다. 매매가, 내일 기온, 당뇨 진행 정도처럼 “얼마인가”를 맞히는 문제입니다. 예측값과 정답 사이의 거리 \(\lvert y - \hat{y} \rvert\)가 의미를 가집니다.
- 분류(classification): 타깃이 정해진 \(K\)개의 라벨 중 하나, 즉 \(y \in \{1, 2, \dots, K\}\)입니다. 악성/양성처럼 둘 중 하나를 고르는 이진 분류는 \(y \in \{0, 1\}\)로 씁니다. 라벨 사이에는 크기 순서가 없습니다. 라벨 2가 라벨 1의 두 배라는 뜻이 아니라, 그저 이름표에 붙인 번호입니다.
같은 대상도 타깃을 어떻게 잡느냐에 따라 문제 종류가 바뀝니다. 종양 데이터에서 “종양 크기(mm)”를 맞히면 회귀지만, “악성인가 양성인가”를 맞히면 분류입니다. 문제가 회귀인지 분류인지에 따라 쓰는 모델과 성능을 재는 방법이 달라지므로, 데이터를 받으면 타깃부터 확인하는 것이 순서입니다.
용어 정리
앞으로 계속 쓸 단어와 기호를 여기서 못 박아 둡니다.
- 특성(feature): 모델의 입력. 표에서 한 열에 해당하며 보통 여러 개입니다. 샘플 \(n\)개의 특성 벡터를 행으로 쌓은 행렬을 관례적으로 대문자 \(X\)로 쓰며, \(X \in \mathbb{R}^{n \times d}\)입니다. 행 하나가 샘플, 열 하나가 특성입니다.
- 타깃(target): 모델이 맞혀야 할 정답. 열 하나이며 소문자 \(\mathbf{y} = (y_1, \dots, y_n)\)으로 씁니다.
- 샘플(sample): 데이터 한 줄, 즉 쌍 \((\mathbf{x}_i, y_i)\) 하나. 표에서 한 행입니다.
- 학습(fit): 데이터를 보고 모델 내부의 값을 정하는 과정. scikit-learn에서
model.fit(X, y)입니다. - 예측(predict): 학습한 모델에 새 입력을 넣어 타깃을 내놓는 것.
model.predict(X)입니다. - 파라미터(parameter): 학습으로 정해지는 모델 내부의 수. 선형 모델이라면 각 특성에 곱해지는 계수와 절편이 파라미터입니다. 파라미터 전체를 묶어 그리스 문자 \(\theta\)(세타)로 쓰는 관례가 있습니다.
- 모델(model): 특성을 받아 예측을 내놓는 함수 \(f_\theta\). 그 함수의 모양은 파라미터 \(\theta\)로 결정됩니다.
모델은 함수의 집합, 학습은 파라미터 찾기
지도학습의 핵심을 한 문장으로 줄이면 이렇습니다. 모델은 파라미터를 가진 함수족이고, 학습은 데이터에 가장 잘 맞는 파라미터를 찾는 일이다.
선형 회귀를 예로 들면, 모델이 표현하는 함수는 이 꼴입니다.
\[f_{\mathbf{w}, b}(\mathbf{x}) = w_1 x_1 + w_2 x_2 + \cdots + w_d x_d + b = \mathbf{w}^\top \mathbf{x} + b\]특성 \(x_1, \dots, x_d\)는 데이터가 주는 값이고, 각 특성에 곱해지는 가중치 \(\mathbf{w} = (w_1, \dots, w_d)\)와 절편 \(b\)가 파라미터입니다. 가운데 식을 벡터 내적으로 줄여 쓴 것이 \(\mathbf{w}^\top \mathbf{x} + b\)이고, 앞으로는 이 표기를 주로 씁니다. 파라미터를 하나로 묶으면 \(\theta = (\mathbf{w}, b)\), 개수로는 \(d + 1\)개입니다.
파라미터를 어떻게 정하느냐에 따라 이 식은 무수히 많은 서로 다른 함수가 됩니다. 이 “가능한 함수 전체의 모임”이 함수족이며, 수식으로는 이렇게 씁니다.
\[\mathcal{H} = \{ f_\theta : \theta \in \Theta \}\]위 식의 \(\Theta\)는 파라미터가 가질 수 있는 값 전체의 집합입니다. 학습이란 이 \(\mathcal{H}\) 안에서 우리 데이터를 가장 잘 설명하는 함수 하나를 골라내는 것입니다. “가장 잘 설명한다”를 못 맞힌 정도를 재는 손실 함수 \(L\)로 수치화하면, 학습은 다음 최적화 문제가 됩니다.
\[\hat{\theta} = \arg\min_{\theta \in \Theta} \, L(\theta; D)\]기호 \(\arg\min\)은 “\(L\)을 가장 작게 만드는 \(\theta\)“라는 뜻입니다. \(\min L\)이 손실의 최솟값 자체라면, \(\arg\min\)은 그 최솟값이 달성되는 자리, 즉 파라미터 값을 가리킵니다.
그래서 fit이 하는 일은 결국 이 \(\hat{\theta}\)를 구하는 것입니다. 손실 \(L\)을 구체적으로 무엇으로 정의하는지(3편: 손실 함수), 그리고 \(\arg\min\)을 실제로 어떻게 찾는지(4편: 경사하강법)는 뒤에서 다룹니다. 지금은 학습의 결과가 파라미터 값 \(\hat{\theta}\)라는 그림만 잡으면 충분합니다.
회귀 실습: 선형 회귀
scikit-learn 내장 당뇨 데이터로 회귀를 확인합니다. 특성 10개(나이, BMI, 혈압 등)로 1년 뒤 당뇨 진행 정도라는 연속값을 예측하는 문제입니다. 기호로는 \(n = 442\), \(d = 10\), 그러니까 \(X \in \mathbb{R}^{442 \times 10}\)입니다.
1
2
3
4
5
6
7
8
9
10
11
from sklearn.datasets import load_diabetes
from sklearn.linear_model import LinearRegression
X, y = load_diabetes(return_X_y=True)
X.shape # (442, 10): 샘플 442개, 특성 10개
model = LinearRegression()
model.fit(X, y) # 학습: 데이터에 맞는 파라미터를 찾는다
model.coef_.shape # (10,): 특성마다 계수 하나
model.intercept_ # 절편 = 152.13
fit 한 줄로 모델은 계수 10개와 절편 1개, 합쳐서 파라미터 \(d + 1 = 11\)개를 정했습니다. model.coef_가 \(\hat{\mathbf{w}}\), model.intercept_가 \(\hat{b}\)이고, 학습된 모델은 다음 함수입니다.
이 파라미터가 곧 학습된 모델입니다. 이제 예측을 뽑고 성능을 봅니다.
1
2
3
4
model.predict(X[:3]).round(1) # [206.1 68.1 176.9]: 예측값
y[:3] # [151. 75. 141.]: 실제값
model.score(X, y) # 0.5177: R², 1에 가까울수록 잘 맞음
예측값과 실제값이 방향은 비슷하되 정확히 일치하지는 않습니다. 앞에서 본 \(y = f^{*}(\mathbf{x}) + \varepsilon\)의 노이즈 때문에라도, 회귀에서 완벽한 일치는 목표도 기대도 아닙니다. score가 돌려주는 결정계수 \(R^2\)는 이 모델이 타깃의 변동을 얼마나 설명하는지를 나타냅니다.
분자는 모델이 남긴 오차의 제곱합이고, 분모는 아무 특성도 쓰지 않고 타깃 평균 \(\bar{y}\)로만 예측했을 때의 제곱합입니다. 모델이 “평균으로 찍기”보다 나을수록 1에 가까워집니다(회귀 평가는 9편에서 자세히 다룹니다).
분류 실습: 로지스틱 회귀
이번에는 유방암 데이터입니다. 특성 30개(종양의 크기, 질감, 대칭성 등)로 악성인지 양성인지를 맞히는 이진 분류입니다. 타깃은 0(악성)과 1(양성) 두 값뿐입니다.
1
2
3
4
5
6
7
8
9
10
11
12
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
Xc, yc = load_breast_cancer(return_X_y=True)
Xc.shape # (569, 30): 샘플 569개, 특성 30개
yc[:10] # [0 0 0 0 0 0 0 0 0 0]: 타깃은 0/1 라벨
clf = LogisticRegression(max_iter=5000) # 특성 스케일 차이가 커 반복 횟수를 늘림
clf.fit(Xc, yc) # 학습
clf.predict(Xc[:10]) # [0 0 0 0 0 0 0 0 0 0]: 라벨 예측
clf.score(Xc, yc) # 0.9578: 정확도(맞힌 비율)
이름은 “회귀”지만 로지스틱 회귀는 분류 모델입니다. 먼저 회귀 때와 같은 선형식으로 점수 \(z\)를 계산하고, 시그모이드(sigmoid) 함수 \(\sigma\)로 그 점수를 0과 1 사이의 확률로 변환합니다.
\[z = \mathbf{w}^\top \mathbf{x} + b, \qquad \hat{P}(y = 1 \mid \mathbf{x}) = \sigma(z) = \frac{1}{1 + e^{-z}}\]시그모이드는 아무리 큰 \(z\)도 1 아래로, 아무리 작은 \(z\)도 0 위로 눌러 담아, 실수 전체를 확률로 바꿔 줍니다. 판정은 이 확률이 절반을 넘는지로 합니다.
\[\hat{y} = \begin{cases} 1 & \sigma(z) \ge 0.5 \\ 0 & \sigma(z) < 0.5 \end{cases}\]그런데 \(\sigma(z) \ge 0.5\)는 정확히 \(z \ge 0\)일 때이므로, 판정을 가르는 경계는 결국 선형식 \(\mathbf{w}^\top \mathbf{x} + b = 0\)입니다. 여기서도 학습이 하는 일은 같습니다. 이 선형식의 계수와 절편이라는 파라미터를 데이터에 맞게 정하는 것입니다. 분류 모델의 구조는 10편에서, score가 돌려준 정확도만으로는 부족한 이유와 대안은 8편에서 이어집니다.
목표는 훈련 성능이 아니라 일반화
위 두 예제에는 함정이 하나 있습니다. 학습에 쓴 바로 그 X로 score를 쟀다는 점입니다. 모델은 그 데이터에 맞도록 파라미터를 정했으니, 같은 데이터에서의 점수는 실제 실력보다 부풀려지기 쉽습니다. 극단적으로는 데이터를 통째로 외운 모델이 훈련 점수는 만점이면서 새 데이터에서는 쓸모없을 수도 있습니다.
이 문제를 수식의 언어로 옮기면 이렇습니다. 훈련 데이터도, 앞으로 만날 새 데이터도 같은 분포 \(P(\mathbf{x}, y)\)에서 서로 독립적으로 뽑힌다고 가정합니다(i.i.d. 가정).
\[(\mathbf{x}_1, y_1), \dots, (\mathbf{x}_n, y_n) \sim P(\mathbf{x}, y)\]우리가 원하는 것은 손에 쥔 표본 \(D\)를 잘 맞히는 모델이 아니라, 같은 분포 \(P\)에서 새로 뽑힐 데이터도 잘 맞히는 모델입니다. 이것을 일반화(generalization)라고 하며, 훈련 데이터에서 잰 점수는 전자만 말해 줄 뿐 후자를 보장하지 않습니다. 그래서 성능은 학습에 쓰지 않은 데이터로 재야 합니다.
훈련 데이터에서의 점수는 모델의 실력이 아니다. 반드시 학습에 쓰지 않은 데이터로 평가해야 한다.
훈련, 검증, 테스트로 데이터를 나누는 방법과 과대적합과 과소적합은 5편에서 다룹니다. 이번 편의 실습이 훈련 데이터로 점수를 잰 것은 fit/predict/score의 흐름을 최소한으로 보여주기 위한 것일 뿐, 올바른 평가 방식이 아니라는 점을 기억해 두면 됩니다.
정리
| 개념 | 한 줄 요약 |
|---|---|
| 지도학습 | 데이터 \(D = \{(\mathbf{x}_i, y_i)\}_{i=1}^{n}\)에서 \(f: \mathcal{X} \to \mathcal{Y}\)를 근사하는 문제 |
| 회귀 / 분류 | \(y \in \mathbb{R}\)이면 회귀, \(y \in \{1, \dots, K\}\)면 분류 |
| 특성 / 타깃 | 입력 행렬 \(X \in \mathbb{R}^{n \times d}\), 맞힐 정답 \(\mathbf{y}\) |
| 학습 / 예측 | fit은 \(\hat{\theta} = \arg\min_\theta L(\theta; D)\)를 구하고, predict는 \(f_{\hat{\theta}}\)로 새 입력에 답한다 |
| 모델 = 함수족 | \(\mathcal{H} = \{f_\theta : \theta \in \Theta\}\). 학습은 그중 하나를 고르는 것 |
| 목표 = 일반화 | 훈련 점수가 아니라 같은 분포 \(P\)에서 새로 뽑힐 데이터에서의 성능 |
다음 편에서는 “가장 잘 맞는다”를 무엇으로 재는지, 즉 위의 \(L\) 자리에 들어갈 손실 함수를 다룹니다.
다음 글: 머신러닝 기초 (3) - Loss Functions: What the Model Minimizes