我们都知道,方差是用来描述数据离散程度的,但那是在一维的情况下,当遇到多维数据的时候,我们可以为每一维度计算各自的方差。然而, 每一维度的数据并不会是独立的,比如身高和体重就存在一定的关联,如果我们只考虑各个维度的方差,难免会丢失一些信息,因此,便引入了协方差矩阵。
我们先来看看协方差矩阵的数学公式定义:
cov ( X , Y ) = ∑ i = 1 n ( X i − X ‾ ) ( Y i − Y ‾ ) n − 1 \operatorname{cov}(\mathrm{X}, \mathrm{Y})=\frac{\sum_{\mathrm{i}=1}^{\mathrm{n}}\left(\mathrm{X}_{\mathrm{i}}-\overline{\mathrm{X}}\right)\left(\mathrm{Y}_{\mathrm{i}}-\overline{\mathrm{Y}}\right)}{\mathrm{n}-1} cov(X,Y)=n−1∑i=1n(Xi−X)(Yi−Y)
在这里我们假设有 N N N个样本,每个样本是 M M M维向量,那么这 N N N个样本的协方差矩阵应该是一个 M ∗ M M * M M∗M的矩阵,矩阵中的每一个元素 ( i , j ) (i,j) (i,j)代表第 i i i维和第 j j j维之间的协方差,因此,矩阵主对角线的值应该是每一维数据的方差。
当遇到实际要计算协方差矩阵的时候,你可能会觉得十分复杂,没事,python早已有人帮你写好了!
–
在Numpy中,已经写好了计算协方差矩阵的函数:np.cov
,下面我们来调用试试吧
首先假设我们有5个样本,每个样本是3维的数据,样本数据如下:
import numpy as np
data = np.array([[1, 4, 2], [5, 6, 24], [15, 1, 5], [7,3,8], [9,4,7]])
print(data)
打印出来如下:
[[ 1 4 2]
[ 5 6 24]
[15 1 5]
[ 7 3 8]
[ 9 4 7]]
计算协方差矩阵:
np_cov = np.cov(data.T, bias=False)
print(np_cov)
打印出来如下:
[[26.8 -6.8 -6.1 ]
[-6.8 3.3 10.85]
[-6.1 10.85 73.7 ]]
这里要注意的是np.cov()
函数,在你传入的数据时候需要进行矩阵转置,因为它默认每一列是一个样本,每一行才是样本的维度,同时bias的值默认归一化False
为 N − 1 N-1 N−1,如果bias为True
,则归一化为 N N N。其中 N N N为给定的观测次数,也就是样本的数量。
我们知道Tensorflow中每个变量都是一个Tensor
,因此无法使用numpy包进行处理(或者处理比较麻烦),于是,干脆自己写一个计算协方差矩阵的函数。按照协方差矩阵的定义:
import tensorflow as tf
def tf_cov(x):
mean_x = tf.reduce_mean(x, axis=0, keepdims=True)
cov_xx = tf.matmul(tf.transpose(x-mean_x), x-mean_x)/tf.cast(tf.shape(x)[0]-1, tf.float64)
return cov_xx
我们试着调用一下这个函数tf_cov()
data = np.array([[1, 4, 2], [5, 6, 24], [15, 1, 5], [7,3,8], [9,4,7]])
with tf.Session() as sess:
print(sess.run(tf_cov(tf.constant(data, dtype=tf.float64))))
结果显示:
[[26.8 -6.8 -6.1 ]
[-6.8 3.3 10.85]
[-6.1 10.85 73.7 ]]
和上面一样的结果!
记住这里,bias如果为True
则代码中
cov_xx = tf.matmul(tf.transpose(x-mean_x), x-mean_x)/tf.cast(tf.shape(x)[0]-1, tf.float64)
应该改为:
cov_xx = tf.matmul(tf.transpose(x-mean_x), x-mean_x)/tf.cast(tf.shape(x)[0], tf.float64)
即去掉-1
.
至此,我们完成了对协方差矩阵的计算,协方差矩阵在机器学习中有着很大的左右,例如计算马氏距离等等。这些就留着过后进行探索了。