QDA & LDA

QDA와 LDA

확률론적 생성모형에서는 베이즈 정리를 사용하여 조건부확률을 계산한다고 했다.

하나의 독립변수 x에 대해 y가 k일 경우의 조건부확률을 모두 구해서 그 중 가장 값이 큰 y로 추정하는데, 위 베이즈정리 공식에서 분모는 P(x)이므로 이 때 분모값은 고정이다. 따라서 확률의 크기만을 비교해도 되는 경우에는 현실적으로 분모를 따로 구하지 않고 분자만을 계산해 비교하여 클래스를 판별하기도 한다.

여기서 사전확률, 즉 $P(y=k)$ 는 다음처럼 계산한다.

그리고 가능도 $P(x \mid y=k)$ 는 다음과 같이 계산한다.

  1. $P(x \mid y= k)$ 가 특정한 확률분포 모형을 따른다고 가정한다.

  2. k번째 클래스에 속하는 학습데이터 {$x_1, \cdots , x_{N}$} 을 사용하여 이 모형의 모수 값을 구한다.

  3. 모수값을 알고 있으므로 $P(x \mid y=k)$ 의 확률밀도함수를 구한 것이다. 즉, 새로운 독립변수가 어떤 x가 되더라도 가능도를 구할 수 있다.

QDA

베이즈 정리를 사용하여 조건부확률 $p(y=k\mid x)$ 을 계산하는 확률적 생성모형 중에서, 독립변수 x가 다변수 가우시안 정규분포(Multivariable Gaussian Normal distribution)을 따른다고 가정하는 모형이 QDA(Quadratic Discriminant Analysis)이다.

  • $\sum_k$ : k클래스에 해당하는 x들의 공분산행렬

  • $\mu_k$ : 1클래스에 해당하는 x들의 평균

이 분포들을 알고 있으면 독립변수 x에 대한 y의 조건부확률 분포는 다음과 같이 베이즈 정리와 전체확률의 법칙으로 구할 수 있다.

예를 들어 y가 1, 2, 3 세 개의 클래스를 가지고, 각 클래스에서의 x의 확률분포가 다음과 같은 기댓값 및 공분산행렬을 갖는다고 가정하자.

y의 사전확률은 다음과 같이 동일하다.

Scikit-Learn은 QDA 모형을 위한QuadraticDiscriminantAnalysis 클래스를 제공한다. 이 클래스로 위에서 가정한 바에 따라 모형을 만들어 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
N = 100
np.random.seed(0)
X1 = sp.stats.multivariate_normal([0, 0], [[0.7, 0], [0, 0.7]]).rvs(100)
X2 = sp.stats.multivariate_normal([1, 1], [[0.8, 0.2], [0.2, 0.8]]).rvs(100)
X3 = sp.stats.multivariate_normal([-1, 1], [[0.8, 0.2], [0.2, 0.8]]).rvs(100)
y1 = np.zeros(N)
y2 = np.ones(N)
y3 = 2*np.ones(N)
X = np.vstack([X1, X2, X3])
y = np.hstack([y1, y2, y3])

from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis
qda = QuadraticDiscriminantAnalysis(store_covariance=True).fit(X, y)
#store_covariance=True로 놓으면 공분산행렬을 제공한다
1
2
3
4
5
6
qda.means_ #각 클래스에서의 추정된 기댓값 벡터 

#결과
array([[-8.01254084e-04, 1.19457204e-01], # class 1일 때
[ 1.16303727e+00, 1.03930605e+00], # 2일 때
[-8.64060404e-01, 1.02295794e+00]])# 3일 때
1
2
3
4
5
6
7
qda.covariance_ #공분산행렬

#결과
[array([[ 0.73846319, -0.01762041],
[-0.01762041, 0.72961278]]), array([[0.66534246, 0.21132313],
[0.21132313, 0.78806006]]), array([[0.9351386 , 0.22880955],
[0.22880955, 0.79142383]])]

이 확률분포를 사용하여 분류를 한 결과는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
x1min, x1max = -5, 5
x2min, x2max = -4, 5
XX1, XX2 = np.meshgrid(np.arange(x1min, x1max, (x1max-x1min)/1000),
np.arange(x2min, x2max, (x2max-x2min)/1000))
YY = np.reshape(qda.predict(np.array([XX1.ravel(), XX2.ravel()]).T), XX1.shape)
cmap = mpl.colors.ListedColormap(sns.color_palette(["r", "g", "b"]).as_hex())
plt.contourf(XX1, XX2, YY, cmap=cmap, alpha=0.5)
plt.scatter(X1[:, 0], X1[:, 1], alpha=0.8, s=50, marker="o", color='r', label="클래스 1")
plt.scatter(X2[:, 0], X2[:, 1], alpha=0.8, s=50, marker="s", color='g', label="클래스 2")
plt.scatter(X3[:, 0], X3[:, 1], alpha=0.8, s=50, marker="x", color='b', label="클래스 3")
plt.xlim(x1min, x1max)
plt.ylim(x2min, x2max)
plt.xlabel("x1")
plt.ylabel("x2")
plt.title("QDA 분석 결과")
plt.legend()
plt.show()

이 그래프는 predict 결과를 등고선으로 나타낸 것이다. 경계선이 그려진 영역에서 높이가 구분되고, 다른 곳은 높이가 일정한 평지이다.

각 영역에 다른 색깔로 misclassification된 데이터들이 많지만 그건 어쩔 수가 없다.

  • QDA의 약점

    모형을 만들어 예측하려면 독립변수들의 Covariance 행렬을 먼저 추정해내야 한다는 점이다. 데이터가 적을 때는 괜찮지만 현실에서 데이터가 수천 수만개가 되면, 공분산 행렬의 크기는 데이터수의 제곱만큼 커지게 된다.

    데이터가 많아질수록 공분산행렬에는 노이즈가 많아지고, 추정도 부정확하게 된다.

LDA(Linear discriminant analysis)

LDA(Linear Discriminant Analysis)에서는 클래스별로 중심의 위치만 다를 뿐 데이터의 분포는 같다고 가정한다. 즉, 각 클래스 y에 대한 독립변수 x의 조건부 확률분포가 공통된 공분산 행렬을 갖는 다변수 가우시안 정규분포라고 가정한다.

이러한 가정은 현실과는 다를 수 있지만 데이터 자체에 노이즈가 섞이는 것을 막아주어, 분류가 qda보다 오히려 정확하게 이루어질 수 있다. 각 class 영역을 구분하는 경계가 곡선이었던 QDA와 달리 LDA에서는 직선이 된다.

Scikit-Learn은 LDA 모형을 위한 LinearDiscriminantAnalysis 클래스를 제공한다. 아래 사용한 데이터는 위 QDA를 진행했던 것과 같은 데이터다.

1
2
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda = LinearDiscriminatAnalysis(n_components=3, solver='svd', store_covariance=True).fit(X, y)

LDA에서는 기댓값 벡터만 클래스에 따라 달라지고, 공분산행렬은 모든 클래스에 대해 하나로 동일하다.

1
2
3
4
5
lda.means_
#결과
array([[-8.01254084e-04, 1.19457204e-01],
[ 1.16303727e+00, 1.03930605e+00],
[-8.64060404e-01, 1.02295794e+00]])
1
2
3
4
lda.covariance_
#결과
array([[0.7718516 , 0.13942905],
[0.13942905, 0.7620019 ]])

LDA 모형에 따른 분류 결과는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
x1min, x1max = -5, 5
x2min, x2max = -4, 5
XX1, XX2 = np.meshgrid(np.arange(x1min, x1max, (x1max-x1min)/1000),
np.arange(x2min, x2max, (x2max-x2min)/1000))
YY = np.reshape(lda.predict(np.array([XX1.ravel(), XX2.ravel()]).T), XX1.shape)
cmap = mpl.colors.ListedColormap(sns.color_palette(["r", "g", "b"]).as_hex())
plt.contourf(XX1, XX2, YY, cmap=cmap, alpha=0.5)
plt.scatter(X1[:, 0], X1[:, 1], alpha=0.8, s=50, marker="o", color='r', label="클래스 1")
plt.scatter(X2[:, 0], X2[:, 1], alpha=0.8, s=50, marker="s", color='g', label="클래스 2")
plt.scatter(X3[:, 0], X3[:, 1], alpha=0.8, s=50, marker="x", color='b', label="클래스 3")
plt.xlim(x1min, x1max)
plt.ylim(x2min, x2max)
plt.xlabel("x1")
plt.ylabel("x2")
plt.legend()
plt.title("LDA 분석 결과")
plt.show()

  • LDA의 약점

    문제는, LDA에서도 데이터가 너무 많아지면 공분산행렬이 너무 커진다는 점이다. 그래서 나온 가정이 공분산행렬의 대각성분만 구하고 나머지 비대각성분은 0이라고 하자는 나이브 가정이다.

    QDA를 간략화한 모형이 LDA이고, 그걸 더 간략화한 모형이 다음 설명할 나이브베이즈 모형이다.

참조:

Share