在 PCA 中用到协方差阵的计算以及特征值和特征向量的计算。
numpy.cov()
函数用来计算协方差
a, b = np.linalg.eig(x)
函数可以用来计算矩阵的特征值与特征向量
numpy.linalg.inv()
函数用来计算可逆矩阵的逆矩阵。
协方差矩阵
1. 协方差定义
X、Y 是两个随机变量,X、Y 的协方差 cov(X, Y) 定义为:
\[\operatorname{cov}(X, Y)=E\left[\left(X-\mu_{x}\right)\left(Y-\mu_{y}\right)\right]\]其中:
\[E(X)=\mu_{x}, E(Y)=\mu_{y}\]2. 协方差矩阵定义
矩阵中的数据按行排列与按列排列求出的协方差矩阵是不同的,这里默认数据是按行排列。即每一行是一个observation(or sample),那么每一列就是一个随机变量。
\[X_{m \times n}=\left[\begin{array}{cccc}{a_{11}} & {a_{12}} & {\cdots} & {a_{1 n}} \\ {a_{21}} & {a_{22}} & {\cdots} & {a_{2 n}} \\ {\vdots} & {\vdots} & {\vdots} & {\vdots} \\ {a_{m 1}} & {a_{m 2}} & {\cdots} & {a_{m n}}\end{array}\right]=\left[\begin{array}{llll}{c_{1}} & {c_{2}} & {\cdots} & {c_{n}}\end{array}\right]\]协方差矩阵:
\[\text { covMatrix }=\frac{1}{m-1}\left[\begin{array}{cccc}{\operatorname{cov}\left(c_{1}, c_{1}\right)} & {\operatorname{cov}\left(c_{1}, c_{2}\right)} & {\cdots} & {\operatorname{cov}\left(c_{1}, c_{n}\right)} \\ {\operatorname{cov}\left(c_{2}, c_{1}\right)} & {\operatorname{cov}\left(c_{2}, c_{2}\right)} & {\cdots} & {\operatorname{cov}\left(c_{2}, c_{n}\right)} \\ {\vdots} & {\vdots} & {\vdots} & {\vdots} \\ {\operatorname{cov}\left(c_{n}, c_{1}\right)} & {\operatorname{cov}\left(c_{n}, c_{2}\right)} & {\cdots} & {\operatorname{cov}\left(c_{n}, c_{n}\right)}\end{array}\right]\]协方差矩阵的维度等于随机变量的个数,即每一个 observation 的维度。在某些场合前边也会出现 $1 / m$ ,而不是 $1 / (m - 1)$ .
3. 求解协方差矩阵的步骤
举个例子,矩阵 X 按行排列:
\[X=\left[\begin{array}{lll}{1} & {2} & {3} \\ {3} & {1} & {1}\end{array}\right]=\left[\begin{array}{lll}{c_{1}} & {c_{2}} & {c_{3}}\end{array}\right]\]-
求每个维度的平均值:
\[\bar{c}=\left[\begin{array}{lll} {2} & {1.5} & {2} \end{array}\right]=\left[\begin{array}{lll} {\bar{c}_{1}} & {\bar{c}_{2}} & {\bar{c}_{3}} \end{array}\right]\] -
将 X 的每一列减去平均值
\[X=\left[\begin{array}{ccc} {-1} & {0.5} & {1} \\ {1} & {-0.5} & {-1} \end{array}\right]\]其中:
-
计算协方差矩阵
\[\operatorname{cov}=\frac{1}{m-1} X^{T} X=\frac{1}{2-1}\left[\begin{array}{ccc} {2} & {-1} & {-2} \\ {-1} & {0.5} & {1} \\ {-2} & {1} & {2} \end{array}\right]\]
4. 意义
协方差的为正,代表两个变量正相关;负,代表两个变量负相关
重点:协方差矩阵计算的是不同维度之间的协方差,而不是不同样本之间。
5. numpy.cov()
计算协方差矩阵
函数
numpy.cov()
的作用是计算协方差矩阵。
def cov(m, y=None, rowvar=True, bias=False,
ddof=None, fweights=None,aweights=None)
m
:一维或则二维的数组,默认情况下每一行代表一个变量(属性),每一列代表一个观测y
:与m
具有一样的形式的一组数据.rowvar
: 默认为True,此时每一行代表一个变量(属性),每一列代表一个观测;为False时,则反之bias
: 默认为False,此时标准化时除以n-1;反之为n。其中n为观测数ddof
:类型是int,当其值非None时,bias参数作用将失效。当ddof
=1时,将会返回无偏估计(除以n-1),即使指定了fweights
和aweights
参数;当ddof
=0时,则返回简单平均值。frequency weights
:一维数组,代表每个观测要重复的次数(相当于给观测赋予权重)analytic weights
:一维数组,代表观测矢量权重。对于被认为“重要”的观察,这些相对权重通常很大,而对于被认为不太重要的观察,这些相对权重较小。如果ddof
= 0,则可以使用权重数组将概率分配给观测向量。
Examples
In [1]: import numpy as np
In [2]: x = np.array([[0, 2], [1, 1], [2, 0]]).T
In [3]: x
Out[3]:
array([[0, 1, 2],
[2, 1, 0]])
In [4]: np.cov(x)
Out[4]:
array([[ 1., -1.],
[-1., 1.]])
>>> x = [-2.1, -1, 4.3]
>>> y = [3, 1.1, 0.12]
>>> X = np.stack((x, y), axis=0)
>>> print(np.cov(X))
[[ 11.71 -4.286 ]
[ -4.286 2.14413333]]
>>> print(np.cov(x, y))
[[ 11.71 -4.286 ]
[ -4.286 2.14413333]]
>>> print(np.cov(x))
11.71
import numpy as np
# 计算协方差的时候,一行代表一个特征
# 下面计算cov(T, S, M)
T = np.array([9, 15, 25, 14, 10, 18, 0, 16, 5, 19, 16, 20])
S = np.array([39, 56, 93, 61, 50, 75, 32, 85, 42, 70, 66, 80])
M = np.asarray([38, 56, 90, 63, 56, 77, 30, 80, 41, 79, 64, 88])
X = np.vstack((T, S, M))
# X每行代表一个属性
# 每列代表一个示例,或者说观测
print(np.cov(X))
# [[ 47.71969697 122.9469697 129.59090909]
# [122.9469697 370.08333333 374.59090909]
# [129.59090909 374.59090909 399. ]]
和方差的区别
>>> a = [1,2,3,4] # 当a是一维向量时
>>> import numpy as np
>>> np.cov(a) # 计算样本方差
array(1.66666667)
>>> np.var(a) # 计算总体方差
1.25
# 下面是 cov(a) 和 var(a)的区别
>>> 1.666666666666666667*3/4
1.25
>>>
矩阵特征值、特征向量
函数
numpy.linalg
的eig()
函数可以用来计算矩阵的特征值与特征向量
a, b = np.linalg.eig(x)
x 为矩阵 得到 a 为特征值,b 为特征向量
numpy.linalg.inv()
函数用来计算可逆矩阵的逆矩阵。
Examples
>>> import numpy as np
>>> x = np.mat([[1,2,3], [4,5,6], [7,8,9]])
# 计算矩阵特征值与特征向量
>>> e, v = np.linalg.eig(x)
# 根据特征值和特征向量得到原矩阵
>>> y = v * np.diag(e) * np.linalg.inv(v)
>>> y
matrix([[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]])
numpy
返回的是矩阵的逆,而不是矩阵本身,特征提取有三个矩阵相乘,中间是对角矩阵,它左边的是逆,右边的是变化矩阵,习惯以为返回的是对角矩阵右边那个矩阵,实际返回的是左边那个,所以numpy
的写法是 $QBQ^{-1}$ 而不是教材里通常的写法$Q^{-1}BQ$
>>> from numpy import linalg as LA
>>> w, v = LA.eig(np.diag((1, 2, 3)))
>>> w; v
array([1., 2., 3.])
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
>>> w, v = LA.eig(np.array([[1, -1], [1, 1]]))
>>> w; v
array([1.+1.j, 1.-1.j])
array([[0.70710678+0.j , 0.70710678-0.j ],
[0. -0.70710678j, 0. +0.70710678j]])