주어진 데이터를 선형회귀법으로 분석하여 어떤 직선적인 경향을 따르는지, 또 주어진 데이터의 주성분을 분석하여 차원을 축소시켜 보는 방법들에 대해 다룬 바 있습니다.
선형회귀법은 트렌드 직선의 비밀(선형회귀), 트렌드 직선의 비밀(선형회귀) #2, 트렌드 직선의 비밀(선형회귀) #3
에 걸쳐서 소개한 바 있었습니다.
PCA은 주성분 분석(Principal Component Analysis)이란?, 주성분 분석(PCA)의 수학적 접근, 주성분 분석(PCA)의 수학적 접근 #2에서 다룬 바 있었습니다.
관련글들을 읽다 보면 선형회귀 및 PCA를 활용한 예제들도 만나볼 수 있으니 참고해 보시기 바랍니다.
선형회귀와 PCA 접근법의 차이점은?
우선, 차이점은 선형회귀는 주어진 데이터를 잘 설명하는 일차 직선을 찾는 문제이고, PCA는 주어진 데이터를 잘 설명하는 벡터(주성분)를 찾는 문제입니다. 하지만,
하지만, PCA에서는 주어진 데이터의 평균을 0으로 만들어 놓고 벡터 주성분을 찾기 때문에 선형 회귀법에서의 $y$절편이 생기지는 않습니다.
또 한가지 결정적인 차이점이 있습니다. 그림을 보시죠.
5개의 데이터에 대해 선형 회귀분석을 할 때, 점 $A, B, C, D, E$에서 직선 $y=ax+b$에 이르는 $y$ 값 간의 거리의 제곱을 최소로 하는 값을 찾는 게 목적이었죠? 구체적으로
$$ \sum_{i=1}^5 (ax_i+b-y_i)^2$$
을 최소로 하는 값 $a,b$를 찾았습니다.
반면 주성분 분석을 보면 아래와 같습니다.
즉 점 $A,B,C,D,E$ 를 벡터로 보고, 이 벡터를 어떤 벡터 $\mathbf{w}$에 정사영 시켰을 때의 생겨나는 수직 벡터들(위의 그림에서 빨간색 선)의 제곱합이 최소가 되는, 길이 1인 벡터 $\mathbf{w}$를 구하는 것입니다.
즉, 최소로 하는 타겟이 아래와 같은 것이죠.
PCA에 대한 자세한 수학적 접근은 주성분 분석(PCA)의 수학적 접근과 주성분 분석(PCA)의 수학적 접근 #2를 참고해 보시기 바랍니다.
이제 직접 python 계산을 통하여 두 방법을 비교해 볼게요
Python Code
데이터 예제는 예전 글에서 썼던 자료를 준비해 봤습니다.
이것의 선형회귀 결과는 관련글에 있습니다. 결론만 말해보면 직선
$$y= ax+b,$$
$$ a= 4.614877~,~b=11.33027$$이 바로 최소제곱법으로 구한 선형 회귀의 결과입니다.
이제 code를 보시죠.
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA # PCA를 사용하기 위한 sklearn library 삽입
from sklearn.linear_model import LinearRegression # 선형회귀를 사용하기 위한 sklearn libarary 삽입
def pca_vs_linearRegression():
data = [[2, 20], # 배달 data
[3, 24],
[6, 36],
[8, 47],
[2.6, 22],
[4.8, 32],
[7, 47],
[4, 42],
[2, 21],
[2.2, 21],
[3.8, 30],
[2.4, 25],
[2.6, 18],
[5.4, 38],
[5.1, 28]
]
data = np.array(data) # list data 를 array로 치환
X, y = data[:, 0], data[:, 1] # 첫번째 열을 X, 두번째 열을 y
# X는 배달 거리, y는 배달시간
model = LinearRegression() # 선형회귀 model 선택
model.fit(X=X.reshape(-1, 1), y=y) # model input type에 맞게 X를 재조정(reshape)
print(model.coef_) # 선형회귀 직선의 기울기(slope) 출력
print(model.intercept_) # 선형회귀 직선의 y절편
if __name__ == '__main__':
pca_vs_linearRegression()
우선 여기까지 코딩하고 결과를 보면,
[4.61487693]
11.330266325025239
과 같이 나옵니다. 예전글에서 구했던 결과와 똑같죠.
또 예전글을 복습하다 보면, 기울기 $a$와 $y$절편 $b$는 각각
$$ a= \frac{\mathbf{Cov}(X,Y)}{\mathbb{V}(X)}~,~ b=\mathbb{E}(Y)-a\mathbb{E}(X)$$
로 구할 수도 있다 했습니다.
이 코드를 추가해 볼까요?
cov_matrix = np.cov(data.T, bias=True) # X,y 의 공분산행렬(covariance) 구하기
print(cov_matrix) # 공분산 행렬 출력
var_X = cov_matrix[0,0] # 공분산 행렬의 (1,1)의 원소가 X의 분산
cov_Xy = cov_matrix[0,1] # 공분산 행렬의 (1,2) 또는 (2,1) 원소가 Cov(X,y)
slope = cov_Xy/var_X # 공식에 따른 기울기
intercept = np.mean(y) - slope*np.mean(X) # 공식에 따른 y절편
print(slope, intercept)
이 부분을 위 코드에 삽입하고 결과를 보면,
[[ 3.4344 15.84933333]
[15.84933333 90.72888889]]
4.614876931438777 11.330266325025232
즉 $\mathbb{V}(X) = 3.4344, \mathbf{Cov}(X,y) = 15.849 $이고 기울기와 $y$절편은 위의 코드와 똑같이 나옵니다.
자, 이제 위 데이터를 PCA로 분석해 봅시다. 다음의 코드를 추가해 보죠.
data_mean = data.mean(axis=0) # data의 열별로 평균을 구함
data -= data_mean # 각 열에서 각열의 평균을 뺌 -> 평균이 0인 데이터로 만들어줌
pca = PCA(n_components=1) # 주성분 1개인 PCA분석 model
pca.fit(data) # 분석 시작
new_axis = pca.components_ # 주성분 벡터 추출
print(new_axis) # 주성분 벡터 출력
print(new_axis[0][1]/new_axis[0][0]) # 주성분 벡터의 기울기구함,
# 예컨대 주성분이 (a,b)이면 b/a가 기울기
이것의 결과를 볼까요?
[[0.17327983 0.98487263]]
5.683711757566156
기울기가 5.683이네요! ($y$절편 따지는 건 무의미하지만, 평균을 0으로 맞춰놓았으니 굳이 따지면 $y$절편은 1이 되겠네요)
이렇듯 선형회귀와 PCA 분석의 결과는 다름을 알 수 있습니다. 최적화시키는 목적함수도 다르고, 데이터 전처리 하는 부분도 다르기 때문입니다.
하지만 중요한 것은 데이터의 노이즈를 줄여 곡선 부분을 없앤 직선으로 볼 것인지, 아니면 데이터의 노이즈를 줄여 차원 자체를 줄일 것인지의 철학 차이에서 오는 결과이므로 어떤 방법이 더 효율적인지는 데이터의 상황과 분석 기법 등에 따라 결정될 것 같습니다.
'수학의 재미' 카테고리의 다른 글
트렌드 직선의 비밀(선형회귀) #3 (0) | 2022.05.12 |
---|---|
트렌드 직선의 비밀(선형회귀) #2 (0) | 2022.05.11 |
트렌드 직선의 비밀(선형회귀) (0) | 2022.05.10 |
댓글