Loading [MathJax]/jax/output/CommonHTML/jax.js
본문 바로가기
수학의 재미/행렬 이론

공분산과 공분산 행렬

by hustler78 2022. 7. 4.
728x90
반응형

어떤 현상이나 타깃을 관찰하다 보면 여러 특징(features)들이 있습니다. 예를 들어

  • 사람을 관찰할 경우 키, 몸무게, 나이 등등
  • 학생 학습 성취도를 관찰할 경우: 국어 점수, 수학 점수 등

그런데 경험적으로 키가 큰 사람이 몸무게도 많이 나가고,  수학 점수가 뛰어난 학생이 과학 점수도 좋은, 이른바 양의 상관관계를 띄는 경우도 있고,  같은 거리를 가는데 느리게 가면 시간이 많이 걸리는 등 속도와 시간의 음의 상관관계도 있고, 또 아예 관계가 없어 보이는 경우도 있습니다. 

 

우린 누구누구랑 상관관계가 아주 쩔어주는 사람들~

 

두 특징(또는 변량, 변수)의 관계를 따지는 유명한 방법이 공분산을 산출해 보는 것입니다.

 

두 변수 X,Y의 공분산은 아래와 같이 정의합니다.

X,Y의 공분산(covariance)

X,Y의 표본(sample, 즉 관찰 데이터) n개가 각각
x1,x2,,xn, y1,y2,,yn 일 때, 공분산은
Cov(X,Y)=1nni=1(xiμx)(yiμy)

여기서
μx,μy 는 각각 X,Y의 평균입니다. 즉,
μx=1nni=1xi , μy=1nni=1yi
입니다.

기댓값 기호 E()를 사용해서 표시해보면 

Cov(X,Y)=E((XμX)(YμY))=E(XY)μxμy=E(XY)E(X)E(Y)

라고도 쓸 수 있습니다.

 

그럼 XX 의 공분산은 뭘까요? 

Cov(X,X)=1nni=1(xiμx)2=V(X)

바로 X의 분산이 됩니다.

 


공분산 행렬(covariance matrix)은 공분산을 원소로 하는 행렬입니다. 

features( 즉, 통계 변량)이 p개 있고,  X1,X2,,Xp 라 합시다. 관찰 데이터는 n개의 sample이 있다 하고요. 이때 공분산 행렬 Cp×p 행렬로써 (i,j) 원소가

 Cij=E(XiXj)E(Xi)E(Xj)

인 행렬입니다.

만일 

Xi 의 샘플이 x1i,x2i,,xni 이고 Xj의 샘플이 x1j,x2j,,xnj 라 하면

Cij=1nnr=1xrixrj1n2nr=1xrinr=1xrj

또는

 

Cij=1nnr=1(xriμi)(xrjμj)

입니다. 첨자 때문에 힘들어 보여도 별 거 covariance의 공식을 떠올리면 별 거 아닙니다.

 


 

그렇다며 공분산 행렬을 쉽게 구하는 방법은 뭘까요?

 

X=(||X1μ1X2μ2Xpμp|||)

라 정의합시다.  μii 번째 변수의 평균(기댓값)입니다.

 

즉 일례로, X의 첫 번째 열은

X1μ1=(x11μ1x21μ1xn1μ1)

입니다. 이때,

 

1nXTX=C

가 됩니다. 일견 당연해 보이지만 살짝 산수를 해 본다면,

1n(XTX)ij=1nnr=1(XT)irXrj=1nnr=1XriXrj=1nnr=1(xriμi)(xrjμj)=Cij

이 성립하죠.

 

 


python으로 공분산 행렬을 구해볼까요?

2022.05.13 - [엑셀] - 트렌드 직선의 비밀(선형회귀) 엑셀실습 #1에서 다루었던 예제를 가지고 분석해 보겠습니다.

어느 배달업체의 빅??데이터

예전 선형회귀 관련 글에서 다루었던 배달업체의 배달 거리와 배달시간 조사내역입니다. 배달 15건을 대상으로 관찰한 데이터입니다.

 

두 가지 방법으로 구해 서로 비교해 보겠습니다. 두 가지 방법은

  1.  수식(1)처럼 공분산의 정의대로 구해보기
  2. python numpy 안의 cov 함수 사용

입니다.

 

code를 보시죠.

 

import numpy as np

def calculate_cov_matrix():
    data = [[2, 20],
            [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]
            ]
    nData = len(data)

    x = np.array(data)
    x_mean = x
    x_mean[:, 0] = x[:, 0] - np.mean(x[:, 0])
    x_mean[:, 1] = x[:, 1] - np.mean(x[:, 1])

    print('mean adjust of data')
    print(x_mean)

    res = x_mean.T @ x_mean / nData

    print('\n')
    print('covariance matrix(from definition):')
    print(res)

    c = np.cov(x.T, bias=True)
    print('\n')
    print('covariance matrix(python function):')
    print(c)

if __name__ == '__main__':
    calculate_cov_matrix()

 

code를 간략히 보시죠.

 

 

 

    nData = len(data)

○ data의 개수 즉, 15를 뜻합니다.

 

 

 

    x = np.array(data)
    x_mean = x
    x_mean[:, 0] = x[:, 0] - np.mean(x[:, 0])
    x_mean[:, 1] = x[:, 1] - np.mean(x[:, 1])

○ 기본적인 numpy 함수들을 쓰기 위해 data를 numpy의 array 형으로 변환합니다. (np.array)

○ x의 각 열에서 각 열의 평균을 빼 준 행렬을 구하기 위해 x와 똑같은 복사본 x_mean을 준비하고

○ 0 열과 1열 각각 의 평균을 각 열에서 빼줍니다.

 

 

 

    res = x_mean.T @ x_mean / nData

X의 transpose와 X의 곱을 구해서 data 개수로 나눠줍니다. 이것이 수식(1)입니다!

 

 

 

    c = np.cov(x.T, bias=True)

numpy에서 제공하는 cov 함수를 사용합니다. 그런데 주의할 점은 

 

numpy의 cov의 input은 행이 통계 변수(features)이고 열이 관찰 데이터가 되게끔 넣어야 한다는 것,

(우리의 X와 행/열이 거꾸로)

 

입니다. 따라서 우리가 위의 code에서 만든 x를 넣으면 안 되고, x.T 를 넣어줘야 한다는 것!!

 

○ bias를 허용합니다. 즉 표본 공분산은 "관찰 데이터의 개수 - 1 = 14 "로 나눠줘야 하나, 관찰데이터의 개수인 15로 나눠주라는 의미입니다. 2022.05.09 - [엑셀] - STDEV 함수에서 다룬 내용과 일맥상통하는 내용입니다.

 

○ 좀 더 자세한 사항은 numpy의 tutorial를 참고하시기 바랍니다.

 

 

 

이제 결과를 한번 보겠습니다.

 

 

 

mean adjust of data
[[ -2.06       -10.06666667]
 [ -1.06        -6.06666667]
 [  1.94         5.93333333]
 [  3.94        16.93333333]
 [ -1.46        -8.06666667]
 [  0.74         1.93333333]
 [  2.94        16.93333333]
 [ -0.06        11.93333333]
 [ -2.06        -9.06666667]
 [ -1.86        -9.06666667]
 [ -0.26        -0.06666667]
 [ -1.66        -5.06666667]
 [ -1.46       -12.06666667]
 [  1.34         7.93333333]
 [  1.04        -2.06666667]]


covariance matrix(from definition):
[[ 3.4344     15.84933333]
 [15.84933333 90.72888889]]


covariance matrix(python function):
[[ 3.4344     15.84933333]
 [15.84933333 90.72888889]]

Process finished with exit code 0

 

직접 절차대로 구해 본 것과 numpy의 cov 함수를 이용한 것이 똑같죠. 

참고로, 만일 unbiased 된 공분산을 구하고 싶을 땐,

 

    c = np.cov(x.T, bias=False)

로 해주면 됩니다. 그러면 결과는

 

 

covariance matrix(python function):
[[ 3.67971429 16.98142857]
 [16.98142857 97.20952381]]

으로  기존과 다르게 나옵니다.

 

이런 분석은 엑셀을 통해서도 많이 이루어지는데요. 엑셀 시트에서는 어떠한 방법으로 공분산 행렬을 구하는지 다음 글에서 알아보도록 하겠습니다.

 

 

728x90
반응형