协方差矩阵介绍及C++/OpenCV/Eigen的三种实现
函數f(x)關于某分布P(x)的期望(expectation)或者期望值(expected value)是指,當x由P產生,f作用于x時,f(x)的平均值。對于離散型隨機變量,這可以通過求和得到:
對于連續型隨機變量可以通過求積分得到:
當概率分布在上下文中指明時,我們可以只寫出期望作用的隨機變量的名稱來進行簡化,例如Ex[f(x)]。如果期望作用的隨機變量也很明確,我們可以完全不寫腳標,就像E[f(x)]。默認地,我們假設E[·]表示對方括號內的所有隨機變量的值求平均。期望是線性的。
方差(variance)衡量的是當我們對x依據它的概率分布進行采樣時,隨機變量x的函數值會呈現多大的差異:
Var(f(x))=E[(f(x)-E[f(x)])2]
當方差很小時,f(x)的值形成的簇比較接近它們的期望值。方差的平方根被稱為標準差(standard deviation)。
協方差(covariance)在某種意義上給出了兩個變量線性相關性的強度以及這些變量的尺度:
Cov(f(x),g(y))=E[(f(x)-E[f(x)])(g(y)-E[g(y)])]
協方差的絕對值如果很大則意味著變量值變化很大并且它們同時距離各自的均值很遠。如果協方差是正的,那么兩個變量都傾向于同時取得相對較大的值。如果協方差是負的,那么其中一個變量傾向于取得相對較大的值的同時,另一個變量傾向于取得相對較小的值,反之亦然。其它的衡量指標如相關系數(correlation)將每個變量的貢獻歸一化,為了只衡量變量的相關性而不受各個變量尺度大小的影響。
協方差和相關性是有聯系的,但實際上不同的概念。它們是有聯系的,因為兩個變量如果相互獨立那么它們的協方差為零,如果兩個變量的協方差不為零那么它們一定是相關的。然而,獨立性又和協方差完全不同的性質。兩個變量如果協方差為零,它們之間一定沒有線性關系。獨立性是比零協方差的要求更強,因為獨立性還排除了非線性的關系。兩個變量相互依賴但是具有零協方差是可能的。
隨機向量x∈Rn的協方差矩陣(covariance matrix)是一個n*n的矩陣,并且滿足:
Cov(x)i,j=Cov(xi,xj)
協方差矩陣的對角元是方差:Cov(xi,xi)=Var(xi).
期望值:在概率論和統計學中,一個離散性隨機變量的期望值(或數學期望、或均值,亦簡稱期望)是試驗中每次可能的結果乘以其結果概率的總和。換句話說,期望值像是隨機試驗在同樣的機會下重復多次,所有那些可能狀態平均的結果,便基本上等同”期望值”所期望的數。需要注意的是,期望值并不一定等同于常識中的”期望”------“期望值”也許與每一個結果都不相等。(換句話說,期望值是該變量輸出值的平均數。期望值并不一定包含于變量的輸出值集合里。)
期望值數學定義:如果X是在概率區間(Ω,P)中的隨機變量,那么它的期望值E[X]的定義是:E[X]=∫ΩXdP,并不是每一個隨機變量都有期望值的,因為有的時候這個積分不存在。如果兩個隨機變量的分布相同,那它們的期望值也相同。
如果X是離散的隨機變量,輸出值為x1,x2,…,和輸出值相應的概率為p1,p2,…(概率和為1)。若級數∑ipixi絕對收斂,那么期望值E[X]是一個無限數列的和:E[X]=∑pixi
期望值性質:
(1)、期望值E是線性函數:E[aX+bY]=aE[X]+bE[Y],X和Y為在同一概率空間的兩個隨機變量(可以獨立或者非獨立),a和b為任意實數。
(2)、一般的說,一個隨機變量的函數的期望值并不等于這個隨機變量的期望值的函數。
(3)、在一般情況下,兩個隨機變量的積的期望值不等于兩個隨機變量的期望值的積。特殊情況是當這兩個隨機變量是相互獨立的時候E[XY]=E[X]E[Y](也就是說一個隨機變量的輸出不會影響另一個隨機變量的輸出)。
在統計學中,當估算變量的期望值時,經常用到的方法是重復測量此變量的值,然后用所得數據的平均值來作為此變量的期望值的估計。在概率分布中,期望值和方差或標準差是一種分布的重要特征。
期望值也可以通過方差計算公式來計算方差:Var(X)=E[X2]-(E[X])2。
方差(Variance):在概率論和統計學中,一個隨機變量的方差描述的是它的離散程度,也就是該變量離其期望值的距離。一個實隨機變量的方差也稱為它的二階炬或二階中心動差,恰巧也是它的二階累積量。這里把復雜說白了,就是將各個誤差將之平方(而非取絕對值),使之肯定為正數,相加之后再除以總數,透過這樣的方式來算出各個數據分布、零散(相對中心點)的程度。繼續延伸的話,方差的算術平方根稱為該隨機變量的標準差(此為相對各個數據點間)。
方差定義:設X為服從分布F的隨機變量,如果E[X]是隨機變數X的期望值(平均數μ=E[X]),隨機變量X或者分布F的方差為: Var(X)=E[(X-μ)2] ,這個定義涵蓋了連續、離散、或兩者都有的隨機變數。方差亦可當作是隨機變數與自己本身的協方差:Var(X)=Cov(X,X)。
方差表示式展開成為:Var(X)=E[X2-2XE[X]+(E[X])2]=E[X2]-2E[X]E[X]+(E[X])2=E[X2]-(E[X])2,上述的表示式可記為”平方的平均減掉平均的平方”。
方差不會是負的。
標準差(Standard Deviation, SD),數學符號σ(sigma),在概率統計中最常使用作為測量一組數值的離散程度之用。標準差定義:為方差開算術平方根,反映組內個體間的離散程度。標準差與期望值之比為標準離差率。
簡單來說,標準差是一組數值自平均值分散開來的程度的一種測量觀念。一個較大的標準差,代表大部分的數值和其平均值之間差異較大;一個較小的標準差,代表這些數值較接近平均值。
總體的標準差:基本定義:
協方差(Covariance):在概率論和統計學中用于衡量兩個變量的總體誤差。而方差是協方差的一種特殊情況,即當兩個變量是相同的情況。期望值分別為E(X)=μ與E(Y)=ν的兩個實數隨機變量X與Y之間的協方差定義為:cov(X,Y)=E((X-μ)(Y-ν)),cov(X,Y)=E(X·Y)- μν.
協方差表示的是兩個變量的總體的誤差,這與只表示一個變量誤差的方差不同。如果兩個變量的變化趨勢一致,也就是說如果其中一個大于自身的期望值,另外一個也大于自身的期望值,那么兩個變量之間的協方差就是正值。如果兩個變量的變化趨勢相反,即其中一個大于自身的期望值,另外一個卻小于自身的期望值,那么兩個變量之間的協方差就是負值。
如果X與Y是統計獨立的,那么二者之間的協方差就是0,這是因為E(X·Y)=E(X)·E(Y)= μν. 但是反過來并不成立,即如果X與Y的協方差為0,二者并不一定是統計獨立的。取決于協方差的相關性η:
更準確地說是線性相關性,是一個衡量線性獨立的無量剛數,其取值在[-1,+1]之間。相關性η=1時稱為”完全線性相關”(相關性η=-1時稱為”完全線性負相關”),此時將Yi對Xi作Y-X散點圖,將得到一組精確排列在直線上的點;相關性數值介于-1到1之間時,其絕對值越接近1表明線性相關性越好,作散點圖得到的點的排布越接近一條直線。
相關性為0(因而協方差也為0)的兩個隨機變量又被稱為是不相關的,或者更準確地說叫做”線性無關”、”線性不相關”,這僅僅表明X與Y兩隨機變量之間沒有線性相關性,并非表示它們之間一定沒有任何內在的(非線性)函數關系,和前面所說的”X、Y二者并不一定是統計獨立的”說法一致。
如果X與Y是實數隨機變量,a與b不是隨機變量,那么根據協方差的定義可以得到:cov(X,X)=var(X), cov(X,Y)=cov(Y,X),cov(aX,bY)=ab cov(X,Y),
對于隨機變量序列X1,…,Xn與Y1,…,Ym,有:
對于隨機變量序列X1,…,Xn,有:
兩個向量變量的協方差cov(X,Y)與cov(Y,X)互為轉置矩陣。
協方差矩陣:在統計學與概率論中,協方差矩陣(也稱離差矩陣、方差-協方差矩陣)是一個矩陣,其i,j位置的元素是第i個與第j個隨機向量(即隨機變量構成的向量)之間的協方差。這是從標量隨機變量到高維度隨機向量的自然推廣。
假設X是以n個隨機變數(其中的每個隨機變數也是一個向量,是一個列向量)組成的行向量,X=[X1,X2,…,Xn].并且μi是其第i個列向量Xi中所有元素的平均值,即μi=E(Xi)。協方差矩陣的第i,j項(第i,j項是一個協方差)被定義為如下形式:∑ij=cov(Xi,Yj)=E[(Xi-μi)(Xj-μj)T]
而協方差矩陣為:
矩陣中的第(i,j)個元素是Xi與Xj的協方差。這個概念是對于標量隨機變數方差的一般化推廣。
協方差矩陣性質:∑=E[(X-E[X])(X-E[X])T]與μ=E(X)滿足下邊的基本性質:
(1)、∑=E(XXT)- μμT
(2)、∑是半正定的和對稱的矩陣
(3)、var(aTX)=aTvar(X)a
(4)、∑≥0
(5)、var(AX+a)=Avar(X)AT
(6)、cov(X,Y)=cov(Y,X)T
(7)、cov(X1+X2,Y)=cov(X1,Y)+cov(X2,Y)
(8)、若p=q,則有cov(X+Y)=var(X)+cov(X,Y)+cov(Y,X)+var(Y)
(9)、cov(AX,BX)=Acov(X,X)BT
(10)、若X與Y是獨立的,則有cov(X,Y)=0
(11)、∑=∑T
其中X,X1與X2是隨機(p*1)向量,Y是隨機(q*1)向量,a是(p*1)向量,A與B是(q*p)矩陣。
以上內容摘自:《深度學習中文版》和?維基百科
以下是分別采用C++和OpenCV實現的計算協方差矩陣code:
#include "funset.hpp"
#include <math.h>
#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "common.hpp"// =============================== 計算協方差矩陣 ============================
// 按行存儲,以行為向量,輸入矩陣mat為m行n列,則協方差矩陣covar為n行n列對稱矩陣,均值mean為1行n列
template<typename _Tp>
int calcCovarMatrix(const std::vector<std::vector<_Tp>>& mat, std::vector<std::vector<_Tp>>& covar, std::vector<_Tp>& mean, bool scale = false)
{const int rows = mat.size();const int cols = mat[0].size();const int nsamples = rows;double scale_ = 1.;if (scale) scale_ = 1. / (nsamples /*- 1*/);covar.resize(cols);for (int i = 0; i < cols; ++i)covar[i].resize(cols, (_Tp)0);mean.resize(cols, (_Tp)0);for (int w = 0; w < cols; ++w) {for (int h = 0; h < rows; ++h) {mean[w] += mat[h][w];}}for (auto& value : mean) {value = 1. / rows * value;}for (int i = 0; i < cols; ++i) {std::vector<_Tp> col_buf(rows, (_Tp)0);for (int k = 0; k < rows; ++k)col_buf[k] = mat[k][i] - mean[i];for (int j = 0; j < cols; ++j) {double s0 = 0;for (int k = 0; k < rows; ++k) {s0 += col_buf[k] * (mat[k][j] - mean[j]);}covar[i][j] = (_Tp)(s0 * scale_);}}return 0;
}int test_calcCovarMatrix()
{std::vector<std::vector<float>> vec{ { 1.2f, 2.5f, 5.6f, -2.5f },{ -3.6f, 9.2f, 0.5f, 7.2f },{ 4.3f, 1.3f, 9.4f, -3.4f } };const int rows{ 3 }, cols{ 4 };fprintf(stderr, "source matrix:\n");fbc::print_matrix(vec);fprintf(stderr, "\nc++ implement calculate covariance matrix:\n");std::vector<std::vector<float>> covar1;std::vector<float> mean1;if (fbc::calcCovarMatrix(vec, covar1, mean1, false/*true*/) != 0) {fprintf(stderr, "C++ implement calcCovarMatrix fail\n");return -1;}fprintf(stderr, "print covariance matrix: \n");fbc::print_matrix(covar1);fprintf(stderr, "print mean: \n");fbc::print_matrix(mean1);fprintf(stderr, "\nc++ opencv calculate covariance matrix:\n");cv::Mat mat(rows, cols, CV_32FC1);for (int y = 0; y < rows; ++y) {for (int x = 0; x < cols; ++x) {mat.at<float>(y, x) = vec.at(y).at(x);}}//std::cout << mat << std::endl;//std::cout << "mat:" << std::endl << mat << std::endl;//cv::Mat means(1, mat.cols, mat.type(), cv::Scalar::all(0));//for (int i = 0; i < mat.cols; i++)// means.col(i) = (cv::sum(mat.col(i)) / mat.rows).val[0];//std::cout << "means:" << std::endl << means << std::endl;//cv::Mat tmp = cv::repeat(means, mat.rows, 1);//cv::Mat mat2 = mat - tmp;//cv::Mat covar = (mat2.t()*mat2) / (mat2.rows /*- 1*/); // (X'*X)/n-1//std::cout << "covar:" << std::endl << covar << std::endl;cv::Mat covar2, mean2;cv::calcCovarMatrix(mat, covar2, mean2, CV_COVAR_NORMAL | CV_COVAR_ROWS/* | CV_COVAR_SCALE*/, CV_32FC1);fprintf(stderr, "print covariance matrix: \n");fbc::print_matrix(covar2);fprintf(stderr, "print mean: \n");fbc::print_matrix(mean2);return 0;
}
執行結果如下:
#include "funset.hpp"
#include <math.h>
#include <iostream>
#include <vector>
#include <string>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include "common.hpp"int test_calcCovarMatrix()
{// reference: https://stackoverflow.com/questions/15138634/eigen-is-there-an-inbuilt-way-to-calculate-sample-covariancestd::vector<std::vector<float>> vec{ { 1.2f, 2.5f, 5.6f, -2.5f },{ -3.6f, 9.2f, 0.5f, 7.2f },{ 4.3f, 1.3f, 9.4f, -3.4f } };const int rows{ 3 }, cols{ 4 };std::vector<float> vec_;for (int i = 0; i < rows; ++i) {vec_.insert(vec_.begin() + i * cols, vec[i].begin(), vec[i].end());}Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> m(vec_.data(), rows, cols);fprintf(stderr, "source matrix:\n");std::cout << m << std::endl;fprintf(stdout, "\nEigen implement:\n");const int nsamples = rows;float scale = 1. / (nsamples /*- 1*/);Eigen::MatrixXf mean = m.colwise().mean();std::cout << "print mean: " << std::endl << mean << std::endl;Eigen::MatrixXf tmp(rows, cols);for (int y = 0; y < rows; ++y) {for (int x = 0; x < cols; ++x) {tmp(y, x) = m(y, x) - mean(0, x);}}//std::cout << "tmp: " << std::endl << tmp << std::endl;Eigen::MatrixXf covar = (tmp.adjoint() * tmp) /*/ float(nsamples - 1)*/;std::cout << "print covariance matrix: " << std::endl << covar << std::endl;return 0;
} 執行結果如下:
由以上結果可見:C++、OpenCV、Eigen實現結果是一致的。 注:以上是按照行存儲,且無scale時的結果,如果要進行scale,在OpenCV中實現時是除以行數(nsamples),而在其它公式中介紹是除以行數-1。
GitHub: https://github.com/fengbingchun/NN_Test https://github.com/fengbingchun/Eigen_Test
總結
以上是生活随笔為你收集整理的协方差矩阵介绍及C++/OpenCV/Eigen的三种实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++11中头文件atomic的使用
- 下一篇: C++11中std::condition