주어진 데이터를 선형회귀법으로 분석하여 어떤 직선적인 경향을 따르는지, 또 주어진 데이터의 주성분을 분석하여 차원을 축소시켜 보는 방법들에 대해 다룬 바 있습니다.
선형회귀법은 트렌드 직선의 비밀(선형회귀), 트렌드 직선의 비밀(선형회귀) #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 값 간의 거리의 제곱을 최소로 하는 값을 찾는 게 목적이었죠? 구체적으로
5∑i=1(axi+b−yi)2
을 최소로 하는 값 a,b를 찾았습니다.
반면 주성분 분석을 보면 아래와 같습니다.

즉 점 A,B,C,D,E 를 벡터로 보고, 이 벡터를 어떤 벡터 w에 정사영 시켰을 때의 생겨나는 수직 벡터들(위의 그림에서 빨간색 선)의 제곱합이 최소가 되는, 길이 1인 벡터 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=Cov(X,Y)V(X) , b=E(Y)−aE(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
즉 V(X)=3.4344,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 |
댓글