ПЦА (Principal Component Analysis) или метода анализе сопствених вредности је један математички апарат који се користи за смањење димензије података губитком најмање количине информација.

Стандардно одступање (девијација)

Оно нам говори, колико у просеку елементи скупа одступају од аритметичке средине скупа $\mu$ . Означава се грчким словом сигма, σ. Формула за њено израчунавање је:

$\sigma = \displaystyle \sqrt{ \frac1 n \displaystyle \sum_{i=1}^n (x_i - \mu )^2}$

Ако се узме у обзир Беселова корекција (Bessel’s correction):

$\sigma = \displaystyle \sqrt{ \frac1 {n-1} \displaystyle \sum_{i=1}^{n} (x_i - \mu )^2}$

Варијанса

Стандардно одступање је квадратни корен варијансе, односно варијанса је $\sigma^2$ .

На пример, мерили смо појаву и добили 6 исхода: 1, 2, 3, 4, 5, 6: . Аритметичка средина очекивог исхода је: (1 + 2 + 3 + 4 + 5 + 6)/6 = 3.5

Апсолутна одступања од средње вредности су: 2.5, 1.5, 0.5, 0.5, 1.5, 2.5.

Варијанса је средња вредност квадрата одступања: $\sigma^2$ = $(2.5^2 + 1.5^2 + 0.5^2 + 0.5^2 + 1.5^2 + 2.5^2)/6 = 17.5/6 ≈ 2.91666$

Очекивана стандардна девијација је σ ≈ 1.70782 Она се може рачунати помоћу пакета Python Numpy:

Пример:

import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6])
sigma_squared = np.var(arr) # 2.91666...
sigma = np.std(arr) # 1.70782...

Сопствене вредности

Када за квадратну матрицу $\boldsymbol A$ помножену вектором $\boldsymbol v$ важи

$\boldsymbol A \boldsymbol v = λ \boldsymbol v$

онда je $\lambda$ сопственa вредност матрице која може бити рационалан, ирационалан или комплексан број.

Пример:

$\left[\begin{array}{ll}2 & 1 \\ 1 & 2\end{array}\right]\left[\begin{array}{l}1 \\ 1\end{array}\right]=\left[\begin{array}{l}3 \\ 3\end{array}\right]=3\left[\begin{array}{l}1 \\ 1\end{array}\right]$

$\lambda_1=3, v_1= \begin{bmatrix} 1 \\ 1\end{bmatrix}$, постоји и други пар

$\lambda_2=3, v_2= \begin{bmatrix}1 \\ -1\end{bmatrix}$

Kao што видимо сопствене вредности иду у пару са сопственим векторима $\boldsymbol v$ и најчеће се израчунавају заједно. Ево примера у Пајтону:

import numpy as np
from numpy import linalg as la
a = np.matrix('2 3; 2 1')  # рационалан број
b = np.matrix('0 2; 1 0')  # ирационалан број
c = np.matrix('0 -1; 1 0') # комплексан број

evalues, evectors = la.eig(a)
print(evalues, evectors)
evalues, evectors = la.eig(b)
print(evalues, evectors)
evalues, evectors = la.eig(c)
print(evalues, evectors)

Даје резултат:

[ 4. -1.] 
 [[ 0.83205029 -0.70710678]
 [ 0.5547002   0.70710678]] 

[ 1.41421356 -1.41421356] 
 [[ 0.81649658 -0.81649658]
 [ 0.57735027  0.57735027]] 

[0.+1.j 0.-1.j] 
 [[0.70710678+0.j         0.70710678-0.j        ]
 [0.        -0.70710678j 0.        +0.70710678j]] 

Коваријанса и матрица коваријансе

Многи подаци могу се приказати као једна колона матрице (једна димензија). Рецимо, висина људи. Наравно подаци могу бити вишеколонски.

На пример, ако имамо две колоне: висина људи ($X$) и животно доба ($Y$) можемо да утврдимо постоји ли међуутицај између висине људи и животног доба.

Коваријанса је таква мера која говори како једна колона утиче на другу.

Формула за израчунавање коваријансе изгледа овако:

$cov(X,Y) = \frac 1 n \displaystyle \sum_{i=1}^n (x_i - \mu_x )(y_i- \mu_y))$,

где су $\mu_x$ и $\mu_y$ средње вредности колона.

  • Ако је коваријанса 0 онда не постоји зависност између колона
  • Ако је коваријанса позитивна онда су димензије у корелацији
  • Ако је коваријанса негативна, онда кажемо да колоне нису у корелацији

Коваријанса практично значи да се раст или опадање вредности једне колоне подудара се са растом или опадањем вредности друге колоне.

За матрицу са више колона користан начин да представите све могуће вредности варијанси-коваријанси између колона назива се матрица коваријансе.

Пример: Посматрајмо матрицу која има 5 колона (features) i садржи узорковања за три субјекта.

import numpy as np
X = np.array([ [0.1, 0.3, 0.4, 0.8, 0.9],
               [3.2, 2.4, 2.4, 0.1, 5.5],
               [10., 8.2, 4.3, 2.6, 0.9]
             ])

print( np.cov(X.T) )

Матрица варијансе-коваријанса ће бити 5*5:

[[25.64333333 20.69333333  9.62166667  5.44166667 -2.83666667]
 [20.69333333 16.74333333  7.67166667  4.54166667 -2.83666667]
 [ 9.62166667  7.67166667  3.80333333  1.72833333  0.07666667]
 [ 5.44166667  4.54166667  1.72833333  1.66333333 -2.45333333]
 [-2.83666667 -2.83666667  0.07666667 -2.45333333  7.05333333]]

Кажемо матрица варијансе-коваријансе јер по дијагонали имамо варијансе, иначе коваријансе.

Ипак, статистичар често користи једну сличну меру корелацију да представи односе колона. Матрица корелације је нормализованa јер вредности ове метрица никад не буду веће од 1 и мање од -1, док вредности коваријансе могу да буду у интервалу (-$\infty$, $\infty$).

Погледати дотатак: декомпозиција матрице коваријансе и корелације.

Коваријанса и ПЦА

Уколико одрадимо декомпозицију сопствених вредности (eig) над матрицом коваријансе добијамо ПЦА.

Иначе, ПЦА можемо добити помоћу sklearn.decomposition.PCA:

import numpy as np
from sklearn.decomposition import PCA
a = np.matrix('1 2 3;3 2 1;2 2 2') 
pca = PCA(n_components=3)
pca.fit(a)
print(pca.explained_variance_ratio_)
print(pca.singular_values_)

Резултат:

[1. 0. 0.]
[2. 0. 0.]

Додатак

Сопствене вредности инверзне матрице

A=np.array([[-1, 2, 3],[4, 4, 4],[7, 8, 9]])
np.linalg.det(A) # -8.00000000
Ainv = np.linalg.inv(A)
print(Ainv)
# array([[-0.5 , -0.75,  0.5 ],
#        [ 1.  ,  3.75, -2.  ],
#        [-0.5 , -2.75,  1.5 ]])
evalues, evectors = np.linalg.eig(A)
print(evalues)
#array([14.57035238, -2.76866464,  0.19831227])
print(evectors)
# array([[-0.22334522, -0.88933863,  0.16029357],
#        [-0.4177778 ,  0.3559482 , -0.79054327],
#        [-0.88066942,  0.28701513,  0.5910561 ]])
evalues, evectors = np.linalg.eig(Ainv)
print(evalues)
#array([ 5.04255243, -0.36118495,  0.06863252])
print(evectors)
# array([[-0.16029357,  0.88933863,  0.22334522],
#        [ 0.79054327, -0.3559482 ,  0.4177778 ],
#        [-0.5910561 , -0.28701513,  0.88066942]])

Може се видети да су сопствне вредности инверзне матрице Ainv реципрочне сопственим вредностима матрице A. Сопствени вектори су остали исти (гледају се колоне).

Сопствене вредности транспоноване матрице

print(A.T)
# array([[-1,  4,  7],
#        [ 2,  4,  8],
#        [ 3,  4,  9]])
evalues, evectors = np.linalg.eig(A.T)
print(evalues)
# array([14.57035238, -2.76866464,  0.19831227])
print(evectors)
# array([[-0.4521481 , -0.96819955, -0.19767353],
#        [-0.59108838, -0.00939939, -0.86530542],
#        [-0.66796453,  0.25000255,  0.46062101]])

У случају транспоноване матрице A.T можемо приметити да су сопствене ведности као и у основне матрице A.

Сличне матрице

Узмимо било коју регуларну матрицу P истог ранга као и A:

P=np.array([[1, 2, 3],[0, -1, 1],[5, 6, -2]])
print(P)
# array([[ 1,  2,  3],
#        [ 0, -1,  1],
#        [ 5,  6, -2]])

Инверзна матрица дате матрице је:

Pinv = np.linalg.inv(P)
print(Pinv)
# array([[-0.19047619,  1.04761905,  0.23809524],
#        [ 0.23809524, -0.80952381, -0.04761905],
#        [ 0.23809524,  0.19047619, -0.04761905]])

Срачунајмо матрицу $B = P^{-1}AP$

B= np.dot(np.dot(Pinv,A),P)

Покажимо да матрица B има исте сопствене вредности као и матрица A:

evalues, evectors = np.linalg.eig(B)
print(evalues)
# array([14.57035238,  0.19831227, -2.76866464])
print(evectors)
# array([[-0.8721102 , -0.73365892, -0.75080589],
#        [ 0.47146025,  0.66416554,  0.63145354],
#        [-0.13095429, -0.14362702,  0.19379613]])

Две матрице су сличне уколико су истог ранга и имају исте сопствене вредности. Притом постоји матрица $P$ тако да важи: $B = P^{-1}AP$.

Ако имамо да је $B^\prime = PAP^{-1}$.

Bprim = np.dot(np.dot(P,A),Pinv)
print(Bprim)
# array([[11.80952381,  9.04761905,  3.23809524],
#        [ 1.57142857,  0.85714286,  0.28571429],
#        [ 8.33333333, -5.33333333, -0.66666667]])
evalues, evectors = np.linalg.eig(Bprim)
print(evalues)
# array([14.57035238, -2.76866464,  0.19831227])
print(evectors)
# array([[-0.88778028, -0.23050169, -0.06625355],
#        [-0.11103922,  0.02324329, -0.25976808],
#        [-0.44667266,  0.97279429,  0.96339556]])

Поновно имамо да су сопствене вредности матрице Bprim истоветне сопственим вредностима матрице А.

Квадрат матрице

Уколико матрица учествује у рекурзивном процесу где се множи са собом и сопствене вредности се множе са собом.

import numpy as np
from numpy import linalg as la
a = np.matrix('2 3; 2 1')  # рационалан број
evalues, evectors = la.eig(a)
print(evalues, evectors)
a2 = np.dot(a,a)
evalues, evectors = la.eig(a2)
print(evalues, evectors)

Резултат:

[ 4. -1.] [[ 0.83205029 -0.70710678]
 [ 0.5547002   0.70710678]]
[16.  1.] [[ 0.83205029 -0.70710678]
 [ 0.5547002   0.70710678]]

Уколико се овај процес понавља сопствене вредности експоненционално расту и процеси постају нестабилни.

Детерминанта као производ сопствених вредности

A=np.array([[-1, 2, 3],[4, 4, 4],[7, 8, 9]])
print(A)
# array([[-1,  2,  3],
#        [ 4,  4,  4],
#        [ 7,  8,  9]])
d=np.linalg.det(A)
print(d)
# -8.000000000000002
evalues, evectors = np.linalg.eig(A)
p = np.prod(evalues)
print(p)
# -7.999999999999996

Kao што се може запазити производ сопствених вредности даје вредност детерминанте.

Декомпозиција коваријансе и корелације

import math
import numpy as np
X = np.array([ [6.7 ,3.0 ,5.2 ,2.3],
[6.3 ,2.5 ,5.0 ,1.9],
[6.5 ,3.0 ,5.2 ,2.0],
[6.2 ,3.4 ,5.4 ,2.3],
[5.9 ,3.0 ,5.1 ,1.8]])
print(X)
# [[6.7 3.  5.2 2.3]
#  [6.3 2.5 5.  1.9]
#  [6.5 3.  5.2 2. ]
#  [6.2 3.4 5.4 2.3]
#  [5.9 3.  5.1 1.8]]
from sklearn.preprocessing import StandardScaler
Xstd = StandardScaler().fit_transform(X)
print(Xstd)
# [[ 1.40069858  0.070014    0.15075567  1.16554303]
#  [-0.07372098 -1.6803361  -1.35680105 -0.77702869]
#  [ 0.6634888   0.070014    0.15075567 -0.29138576]
#  [-0.44232587  1.47029409  1.6583124   1.16554303]
#  [-1.54814054  0.070014   -0.60302269 -1.26267162]]

Добијање матрице коваријансе уз Беселову корекцију (Bessel’s correction)

import numpy as np
mean_vec = np.mean(Xstd, axis=0)
cov = (Xstd - mean_vec).T.dot((Xstd - mean_vec)) / (Xstd.shape[0]-1)
cov
# array([[ 1.25      , -0.12258565,  0.15281551,  0.73394247],
#        [-0.12258565,  1.25      ,  1.17424467,  0.74803974],
#        [ 0.15281551,  1.17424467,  1.25      ,  0.9700779 ],
#        [ 0.73394247,  0.74803974,  0.9700779 ,  1.25      ]])

Исто то помоћу np.cov

cov = np.cov(Xstd.T) 
print(cov)
evalues1, evectors1 = np.linalg.eig(cov)
print(evalues1)
print(evectors1)
# [[ 1.25       -0.12258565  0.15281551  0.73394247]
#  [-0.12258565  1.25        1.17424467  0.74803974]
#  [ 0.15281551  1.17424467  1.25        0.9700779 ]
#  [ 0.73394247  0.74803974  0.9700779   1.25      ]]
# [3.27976032 1.54434939 0.14143111 0.03445917]
# [[-0.21455518  0.82898994 -0.51628672  0.01377558]
#  [-0.53684711 -0.41546653 -0.42808737  0.59659361]
#  [-0.59405179 -0.21351247 -0.11641928 -0.76678644]
#  [-0.55934222  0.30753156  0.73255428  0.23648434]]

Добили смо матрицу коваријансе и њену декомпозицију

corr = np.corrcoef(Xstd.T)
print(corr)
evalues2, evectors2 = np.linalg.eig(corr)
print(evalues2)
print(evectors2)
# [[ 1.         -0.09806852  0.12225241  0.58715398]
#  [-0.09806852  1.          0.93939574  0.59843179]
#  [ 0.12225241  0.93939574  1.          0.77606232]
#  [ 0.58715398  0.59843179  0.77606232  1.        ]]
# [2.62380826 1.23547951 0.11314489 0.02756734]
# [[-0.21455518  0.82898994 -0.51628672  0.01377558]
#  [-0.53684711 -0.41546653 -0.42808737  0.59659361]
#  [-0.59405179 -0.21351247 -0.11641928 -0.76678644]
#  [-0.55934222  0.30753156  0.73255428  0.23648434]]

Добили смо матрицу корелације и њену декомпозицију при чему су сопствени вектори истоветни.

evalues1/evalues2
# array([1.25, 1.25, 1.25, 1.25])

Видимо да су сопствене вредности скалиране.

ПЦА помоћу СВД

СВД (Singular Values Decomposition) је метод разлагања матрице $А$ која није нужно квардратна, без да тражимо коваријансу те матрице. Притом место сопствених врдности добијамо сингуларне вредности.

$A = U \Sigma V^{\mathrm{T}}$, при чему је $U$ лева ортогонална матрица - леви сингуларни вектор, $\Sigma$ регуларна диагонална матрица, а $V^{\mathrm{T}}$ десна ортогонална матрица - десни сингуларни вектор.

Матрица $U$ је ортогонална матрица и за њу важи $UU^{\mathrm{T}}=I$ , а притом је и $U^{\mathrm{T}}=U^{-1}$, и $det(U)={ -1, 1 }$. Слично важи и за матрицу $V$ пошто је и она ортогонална.

Ортогоналне матрице имају сопствене векторе који су нормални.

Зашто СВД декомпозиција ради?

Ако потражимо коваријансу матрице $А$,

$A^{\mathrm{T}}A= (V \Sigma^{\mathrm{T}} U^{\mathrm{T}})U \Sigma V^{\mathrm{T}}= V \Sigma^{\mathrm{T}} \Sigma V^{\mathrm{T}}$.

$AA^{\mathrm{T}}= (U \Sigma V^{\mathrm{T}})V \Sigma^{\mathrm{T}} U^{\mathrm{T}}= U \Sigma \Sigma^{\mathrm{T}} U^{\mathrm{T}}$.

$A^{\mathrm{T}}A$ има исте сопствене вредности као и $AA^{\mathrm{T}}$, а сопствени вектори су $V$ и $U$ у првом и другом случају.

Пример:

a= np.array([[2,2],[-1,1]])
print(a)
u, s, vt = np.linalg.svd(a, full_matrices=True)
print(u)
print(s)
print(vt)
u.shape, s.shape, vt.shape

# [[ 2  2]
#  [-1  1]]
# [[-1.00000000e+00  1.23907179e-16]
#  [ 8.64164897e-17  1.00000000e+00]]
# [2.82842712 1.41421356]
# [[-0.70710678 -0.70710678]
#  [-0.70710678  0.70710678]]
# ((2, 2), (2,), (2, 2))