版權聲明:本文爲博主原創文章,未經博主允許不得轉載。
本文將分別介紹特徵值分解、奇異值分解、及PCA的相關理論概念。
文章末尾將給出Householder矩陣變換、QR算法求解特徵值、特徵向量的代碼
其中,特徵值分解、奇異值分解的相關內容,轉載自:
http://www.cnblogs.com/LeftNotEasy/archive/2011/01/19/svd-and-applications.html
考慮到本文50%以上的部分不是那個哥們的博客原文,所以我搞成原創標題了。。。。
一、特徵值與特徵向量的幾何意義
1. 矩陣乘法
在介紹特徵值與特徵向量的幾何意義之前,先介紹矩陣乘法的幾何意義。
矩陣乘法對應了一個變換,是把任意一個向量變成另一個方向或長度的新向量。在這個變化過程中,原向量主要發生旋轉、伸縮的變化。如果矩陣對某些向量只發生伸縮變換,不產生旋轉效果,那麼這些向量就稱爲這個矩陣的特徵向量,伸縮的比例就是特徵值。
比如:,它對應的線性變換是下面的形式形式:
因爲,這個矩陣乘以一個向量(x,y)的結果是:。由於矩陣M是對稱的,所以這個變換是一個對 x , y 軸的一個拉伸變換。【當M中元素值大於1時,是拉伸;當值小於1時,是縮短】
那麼如果矩陣M不是對稱的,比如:,它所描述的變換如下圖所示:
這其實是在平面上對一個軸進行的拉伸變換【如藍色箭頭所示】,在圖中藍色箭頭是一個最主要的變化方向。變化方向可能有不止一個,但如果我們想要描述好一個變換,那我們就描述好這個變換主要的變化方向就好了。
2. 特徵值分解與特徵向量
如果說一個向量v是方陣A的特徵向量,將一定可以表示成下面的形式:
λ爲特徵向量 v 對應的特徵值。特徵值分解是將一個矩陣分解爲如下形式:
其中,Q是這個矩陣A的特徵向量組成的矩陣,Σ是一個對角矩陣,每一個對角線元素就是一個特徵值,裏面的特徵值是由大到小排列的,這些特徵值所對應的特徵向量就是描述這個矩陣變化方向(從主要的變化到次要的變化排列)。也就是說矩陣A的信息可以由其特徵值和特徵向量表示。
對於矩陣爲高維的情況下,那麼這個矩陣就是高維空間下的一個線性變換。可以想象,這個變換也同樣有很多的變換方向,我們通過特徵值分解得到的前N個特徵向量,那麼就對應了這個矩陣最主要的N個變化方向。我們利用這前N個變化方向,就可以近似這個矩陣(變換)。
總結一下,特徵值分解可以得到特徵值與特徵向量,特徵值表示的是這個特徵到底有多重要,而特徵向量表示這個特徵是什麼。不過,特徵值分解也有很多的侷限,比如說變換的矩陣必須是方陣。
二、奇異值分解
1. 奇異值
特徵值分解是一個提取矩陣特徵很不錯的方法,但是它只是對方陣而言的,在現實的世界中,我們看到的大部分矩陣都不是方陣,比如說有N個學生,每個學生有M科成績,這樣形成的一個N * M的矩陣就不可能是方陣,我們怎樣才能描述這樣普通的矩陣呢的重要特徵呢?奇異值分解可以用來幹這個事情,奇異值分解是一個能適用於任意的矩陣的一種分解的方法:分解形式:
假設A是一個M * N的矩陣,那麼得到的U是一個M * M的方陣(稱爲左奇異向量),Σ是一個M * N的矩陣(除了對角線的元素都是0,對角線上的元素稱爲奇異值),VT(V的轉置)是一個N * N的矩陣(稱爲右奇異向量)。
2. 奇異值與特徵值
那麼奇異值和特徵值是怎麼對應起來的呢?我們將一個矩陣A的轉置乘以 A,並對(AAT)求特徵值,則有下面的形式:這裏V就是上面的右奇異向量,另外還有:
這裏的σ就是奇異值,u就是上面說的左奇異向量。【證明那個哥們也沒給】
奇異值σ跟特徵值類似,在矩陣Σ中也是從大到小排列,而且σ的減少特別的快,在很多情況下,前10%甚至1%的奇異值的和就佔了全部的奇異值之和的99%以上了。也就是說,我們也可以用前r( r遠小於m、n )個的奇異值來近似描述矩陣,即部分奇異值分解:
右邊的三個矩陣相乘的結果將會是一個接近於A的矩陣,在這兒,r越接近於n,則相乘的結果越接近於A。
三、PCA主成份分析
主成分分析(PrincipalComponents Analysis。即PCA,也稱爲K-L變換),是圖像壓縮中的一種最優正交變換。PCA用於統計特徵提取構成了子空間法模式識別的基礎。它從圖像整體代數特徵出發,基於圖像的總體信息進行分類識別。PCA的核心思想是利用較少數量的特徵對樣本進行描述以達到降低特徵空間維數的目的。
1. PCA理論
給定一副N*N大小圖像,將它表示成一個N2*1維向量,向量中元素爲像素點灰度,按行存儲,如下列公式分別表示第i張圖片和n張圖片平均值:
令N2*n矩陣X爲:
注意,矩陣減去平均值相當於將座標系原點移動到平均值位置。
設Q=XXT,則Q是一個N2* N2矩陣:
,Q是方陣
,Q是對稱矩陣。
,Q被成爲協方差矩陣,
,Q的數據量非常龐大
那麼,X中的每個元素xj可以被如下表達:
其中,ei是Q中非零特徵值對應的特徵向量。由特徵向量e1,e2,…,en組成的空間叫做張成特徵空間。對於N*N圖像,e1,e2,…,en是N2*1維相互正交的向量。尺度gji是xj在空間中的座標。
2. 實現PCA
爲了降維,可以對特徵值設定閾值或按照其他準則,尋找協方差矩陣Q中前k個特徵向量。這裏Q十分龐大,對於一副256*256的圖像,Q的大小爲65536*65536!替代方案是,考慮矩陣
.P和Q都是對稱矩陣
.P≠QT
.Q的大小是N2*N2,而P大小爲n*n
.n爲訓練樣本圖像數量,通常n<<N
設e是矩陣P的特徵值λ對應的特徵向量,則有:
這裏,X*e也是矩陣Q的特徵值λ對應的特徵向量【這是用求特徵值分解方法,下面介紹用SVD方法】
3. PCA與奇異值分解SVD
任何一個m*n矩陣都能進行奇異值分解,拆分爲3個矩陣相乘的形式。由於SVD得出的奇異向量也是從奇異值由大到小排列的,按PCA的觀點來看,就是方差最大的座標軸就是第一個奇異向量,方差次大的座標軸就是第二個奇異向量…。我們可以對Q進行奇異值分解。
.U就是QQT的特徵向量
.V就是QTQ的特徵向量
.D中奇異值的平方就是QQT和QTQ的特徵值
=======================================================================================================================
上面講了一大堆,就是爲了下一篇PCA人臉識別做鋪墊的,給你一副圖像,要從圖像庫中得到匹配的圖像,怎麼弄?如果是兩兩做像素點比較是不可能完成的任務,時間上廢掉了。如果用其他特徵點代替也許可以,但容易漏檢吧,這邊不擴展。我們必須對圖像數據的協方差矩陣進行降維,所以用到了PCA。
而具體如何實現PCA呢?關鍵是特徵值及相應特徵向量的求取。matlab有個eig函數,OpenCV也有相應的函數。由於不想被別人牽制,我自己查了資料,發現QR算法可以用來求實對稱矩陣的全部特徵值和特徵向量。【雅可比算法也可以,就是速度太慢了;而上面介紹的SVD實現PCA還沒見過,文獻上說SVD和PCA是等價的】
=======================================================================================================================
以下內容,來自《C常用算法程序集第二版》,這絕對是搞科研的好書!
在用QR算法求解特徵值和向量之前,必須將實對稱矩陣轉化爲三對角矩陣。【由於我們的協方差矩陣是實對稱矩陣,因此不用轉化爲Hessen berg矩陣,QR算法是一個迭代的過程,具體算法太長了,我不貼出來了,有需要的,自己去下載這本書的PDF文檔或其他資料】
1.約化對稱矩陣爲三對角矩陣的Householder變換法:
例:
【其他高維矩陣也行,大家可以把數據存在txt文本中,然後讀取進來】
代碼:
- // HouseHolder_Transform.cpp : 定義控制檯應用程序的入口點。
- //
- #include "stdafx.h"
- #include "math.h"
- void cstrq(double a[],int n,double q[],double b[],double c[]);
- int _tmain(int argc, _TCHAR* argv[])
- {
- int i,j;
- static double b[5],c[5],q[25];
- static double a[25] = {10.0,1.0,2.0,3.0,4.0,1.0,9.0,-1.0,2.0,-3.0,2.0,-1.0,7.0,3.0,-5.0,3.0,2.0,3.0,12.0,-1.0,4.0,-3.0,-5.0,-1.0,15.0};
- cstrq(a,5,q,b,c);
- printf("MAT A is:\n");
- for (i=0;i<5;i++)
- {
- for (j=0;j<5;j++)
- {
- printf("%13.7e ",a[i*5+j]);
- }
- printf("\n");
- }
- printf("\n");
- printf("MAT Q is:\n");
- for (i=0;i<5;i++)
- {
- for (j=0;j<5;j++)
- {
- printf("%13.7e ",q[i*5+j]);
- }
- printf("\n");
- }
- printf("\n");
- printf("MAT B is:\n");
- for (i=0;i<5;i++)
- {
- printf("%13.7e ",b[i]);
- }
- printf("\n\n");
- printf("MAT C is:\n");
- for (i=0;i<5;i++)
- {
- printf("%13.7e ",c[i]);
- }
- printf("\n\n");
- return 0;
- }
- void cstrq(double a[],int n,double q[],double b[],double c[])
- {
- int i,j,k,u,v;
- double h,f,g,h2;
- for (i=0; i<=n-1; i++)
- for (j=0; j<=n-1; j++)
- { u=i*n+j; q[u]=a[u];}
- for (i=n-1; i>=1; i--)
- { h=0.0;
- if (i>1)
- for (k=0; k<=i-1; k++)
- { u=i*n+k; h=h+q[u]*q[u];}
- if (h+1.0==1.0)
- { c[i]=0.0;
- if (i==1) c[i]=q[i*n+i-1];
- b[i]=0.0;
- }
- else
- { c[i]=sqrt(h);
- u=i*n+i-1;
- if (q[u]>0.0) c[i]=-c[i];
- h=h-q[u]*c[i];
- q[u]=q[u]-c[i];
- f=0.0;
- for (j=0; j<=i-1; j++)
- { q[j*n+i]=q[i*n+j]/h;
- g=0.0;
- for (k=0; k<=j; k++)
- g=g+q[j*n+k]*q[i*n+k];
- if (j+1<=i-1)
- for (k=j+1; k<=i-1; k++)
- g=g+q[k*n+j]*q[i*n+k];
- c[j]=g/h;
- f=f+g*q[j*n+i];
- }
- h2=f/(h+h);
- for (j=0; j<=i-1; j++)
- { f=q[i*n+j];
- g=c[j]-h2*f;
- c[j]=g;
- for (k=0; k<=j; k++)
- { u=j*n+k;
- q[u]=q[u]-f*c[k]-g*q[i*n+k];
- }
- }
- b[i]=h;
- }
- }
- for (i=0; i<=n-2; i++) c[i]=c[i+1];
- c[n-1]=0.0;
- b[0]=0.0;
- for (i=0; i<=n-1; i++)
- { if ((b[i]!=0.0)&&(i-1>=0))
- for (j=0; j<=i-1; j++)
- { g=0.0;
- for (k=0; k<=i-1; k++)
- g=g+q[i*n+k]*q[k*n+j];
- for (k=0; k<=i-1; k++)
- { u=k*n+j;
- q[u]=q[u]-g*q[k*n+i];
- }
- }
- u=i*n+i;
- b[i]=q[u]; q[u]=1.0;
- if (i-1>=0)
- for (j=0; j<=i-1; j++)
- { q[i*n+j]=0.0; q[j*n+i]=0.0;}
- }
- return;
- }
// HouseHolder_Transform.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include "math.h"
void cstrq(double a[],int n,double q[],double b[],double c[]);
int _tmain(int argc, _TCHAR* argv[])
{
int i,j;
static double b[5],c[5],q[25];
static double a[25] = {10.0,1.0,2.0,3.0,4.0,1.0,9.0,-1.0,2.0,-3.0,2.0,-1.0,7.0,3.0,-5.0,3.0,2.0,3.0,12.0,-1.0,4.0,-3.0,-5.0,-1.0,15.0};
cstrq(a,5,q,b,c);
printf("MAT A is:\n");
for (i=0;i<5;i++)
{
for (j=0;j<5;j++)
{
printf("%13.7e ",a[i*5+j]);
}
printf("\n");
}
printf("\n");
printf("MAT Q is:\n");
for (i=0;i<5;i++)
{
for (j=0;j<5;j++)
{
printf("%13.7e ",q[i*5+j]);
}
printf("\n");
}
printf("\n");
printf("MAT B is:\n");
for (i=0;i<5;i++)
{
printf("%13.7e ",b[i]);
}
printf("\n\n");
printf("MAT C is:\n");
for (i=0;i<5;i++)
{
printf("%13.7e ",c[i]);
}
printf("\n\n");
return 0;
}
void cstrq(double a[],int n,double q[],double b[],double c[])
{
int i,j,k,u,v;
double h,f,g,h2;
for (i=0; i<=n-1; i++)
for (j=0; j<=n-1; j++)
{ u=i*n+j; q[u]=a[u];}
for (i=n-1; i>=1; i--)
{ h=0.0;
if (i>1)
for (k=0; k<=i-1; k++)
{ u=i*n+k; h=h+q[u]*q[u];}
if (h+1.0==1.0)
{ c[i]=0.0;
if (i==1) c[i]=q[i*n+i-1];
b[i]=0.0;
}
else
{ c[i]=sqrt(h);
u=i*n+i-1;
if (q[u]>0.0) c[i]=-c[i];
h=h-q[u]*c[i];
q[u]=q[u]-c[i];
f=0.0;
for (j=0; j<=i-1; j++)
{ q[j*n+i]=q[i*n+j]/h;
g=0.0;
for (k=0; k<=j; k++)
g=g+q[j*n+k]*q[i*n+k];
if (j+1<=i-1)
for (k=j+1; k<=i-1; k++)
g=g+q[k*n+j]*q[i*n+k];
c[j]=g/h;
f=f+g*q[j*n+i];
}
h2=f/(h+h);
for (j=0; j<=i-1; j++)
{ f=q[i*n+j];
g=c[j]-h2*f;
c[j]=g;
for (k=0; k<=j; k++)
{ u=j*n+k;
q[u]=q[u]-f*c[k]-g*q[i*n+k];
}
}
b[i]=h;
}
}
for (i=0; i<=n-2; i++) c[i]=c[i+1];
c[n-1]=0.0;
b[0]=0.0;
for (i=0; i<=n-1; i++)
{ if ((b[i]!=0.0)&&(i-1>=0))
for (j=0; j<=i-1; j++)
{ g=0.0;
for (k=0; k<=i-1; k++)
g=g+q[i*n+k]*q[k*n+j];
for (k=0; k<=i-1; k++)
{ u=k*n+j;
q[u]=q[u]-g*q[k*n+i];
}
}
u=i*n+i;
b[i]=q[u]; q[u]=1.0;
if (i-1>=0)
for (j=0; j<=i-1; j++)
{ q[i*n+j]=0.0; q[j*n+i]=0.0;}
}
return;
}
計算結果:
即上述計算結果返回的三對角陣T爲:
2.下面,我們將在三對角矩陣的基礎上使用QR算法計算全部特徵值和特徵向量
例,同樣對上面那個5階矩陣,先求三對角矩陣,再求其全部特徵值和特徵向量
最大迭代次數爲60,誤差爲0.000001
代碼:
- #include "stdafx.h"
- #include "math.h"
- void cstrq(double a[],int n,double q[],double b[],double c[]);
- int csstq(int n,double b[],double c[],double q[],double eps,int l);
- int _tmain(int argc, _TCHAR* argv[])
- {
- int i,j,k,l=60;
- static double b[5],c[5],q[25];
- static double a[25] = {10.0,1.0,2.0,3.0,4.0,1.0,9.0,-1.0,2.0,-3.0,2.0,-1.0,7.0,3.0,-5.0,3.0,2.0,3.0,12.0,-1.0,4.0,-3.0,-5.0,-1.0,15.0};
- double eps = 0.000001;
- cstrq(a,5,q,b,c);
- k = csstq(5,b,c,q,eps,l);
- printf("MAT A is:\n");
- for (i=0;i<5;i++)
- {
- for (j=0;j<5;j++)
- {
- printf("%13.7e ",a[i*5+j]);
- }
- printf("\n");
- }
- printf("\n");
- printf("MAT B is:\n");
- for (i=0;i<5;i++)
- {
- printf("%13.7e ",b[i]);
- }
- printf("\n\n");
- printf("MAT Q is:\n");
- for (i=0;i<5;i++)
- {
- for (j=0;j<5;j++)
- {
- printf("%13.7e ",q[i*5+j]);
- }
- printf("\n");
- }
- printf("\n");
- return 0;
- }
- void cstrq(double a[],int n,double q[],double b[],double c[])
- {
- int i,j,k,u,v;
- double h,f,g,h2;
- for (i=0; i<=n-1; i++)
- for (j=0; j<=n-1; j++)
- { u=i*n+j; q[u]=a[u];}
- for (i=n-1; i>=1; i--)
- { h=0.0;
- if (i>1)
- for (k=0; k<=i-1; k++)
- { u=i*n+k; h=h+q[u]*q[u];}
- if (h+1.0==1.0)
- { c[i]=0.0;
- if (i==1) c[i]=q[i*n+i-1];
- b[i]=0.0;
- }
- else
- { c[i]=sqrt(h);
- u=i*n+i-1;
- if (q[u]>0.0) c[i]=-c[i];
- h=h-q[u]*c[i];
- q[u]=q[u]-c[i];
- f=0.0;
- for (j=0; j<=i-1; j++)
- { q[j*n+i]=q[i*n+j]/h;
- g=0.0;
- for (k=0; k<=j; k++)
- g=g+q[j*n+k]*q[i*n+k];
- if (j+1<=i-1)
- for (k=j+1; k<=i-1; k++)
- g=g+q[k*n+j]*q[i*n+k];
- c[j]=g/h;
- f=f+g*q[j*n+i];
- }
- h2=f/(h+h);
- for (j=0; j<=i-1; j++)
- { f=q[i*n+j];
- g=c[j]-h2*f;
- c[j]=g;
- for (k=0; k<=j; k++)
- { u=j*n+k;
- q[u]=q[u]-f*c[k]-g*q[i*n+k];
- }
- }
- b[i]=h;
- }
- }
- for (i=0; i<=n-2; i++) c[i]=c[i+1];
- c[n-1]=0.0;
- b[0]=0.0;
- for (i=0; i<=n-1; i++)
- { if ((b[i]!=0.0)&&(i-1>=0))
- for (j=0; j<=i-1; j++)
- { g=0.0;
- for (k=0; k<=i-1; k++)
- g=g+q[i*n+k]*q[k*n+j];
- for (k=0; k<=i-1; k++)
- { u=k*n+j;
- q[u]=q[u]-g*q[k*n+i];
- }
- }
- u=i*n+i;
- b[i]=q[u]; q[u]=1.0;
- if (i-1>=0)
- for (j=0; j<=i-1; j++)
- { q[i*n+j]=0.0; q[j*n+i]=0.0;}
- }
- return;
- }
- int csstq(int n,double b[],double c[],double q[],double eps,int l)
- {
- int i,j,k,m,it,u,v;
- double d,f,h,g,p,r,e,s;
- c[n-1]=0.0; d=0.0; f=0.0;
- for (j=0; j<=n-1; j++)
- { it=0;
- h=eps*(fabs(b[j])+fabs(c[j]));
- if (h>d) d=h;
- m=j;
- while ((m<=n-1)&&(fabs(c[m])>d)) m=m+1;
- if (m!=j)
- { do
- { if (it==l)
- { printf("fail\n");
- return(-1);
- }
- it=it+1;
- g=b[j];
- p=(b[j+1]-g)/(2.0*c[j]);
- r=sqrt(p*p+1.0);
- if (p>=0.0) b[j]=c[j]/(p+r);
- else b[j]=c[j]/(p-r);
- h=g-b[j];
- for (i=j+1; i<=n-1; i++)
- b[i]=b[i]-h;
- f=f+h; p=b[m]; e=1.0; s=0.0;
- for (i=m-1; i>=j; i--)
- { g=e*c[i]; h=e*p;
- if (fabs(p)>=fabs(c[i]))
- { e=c[i]/p; r=sqrt(e*e+1.0);
- c[i+1]=s*p*r; s=e/r; e=1.0/r;
- }
- else
- { e=p/c[i]; r=sqrt(e*e+1.0);
- c[i+1]=s*c[i]*r;
- s=1.0/r; e=e/r;
- }
- p=e*b[i]-s*g;
- b[i+1]=h+s*(e*g+s*b[i]);
- for (k=0; k<=n-1; k++)
- { u=k*n+i+1; v=u-1;
- h=q[u]; q[u]=s*q[v]+e*h;
- q[v]=e*q[v]-s*h;
- }
- }
- c[j]=s*p; b[j]=e*p;
- }
- while (fabs(c[j])>d);
- }
- b[j]=b[j]+f;
- }
- for (i=0; i<=n-1; i++)
- { k=i; p=b[i];
- if (i+1<=n-1)
- { j=i+1;
- while ((j<=n-1)&&(b[j]<=p))
- { k=j; p=b[j]; j=j+1;}
- }
- if (k!=i)
- { b[k]=b[i]; b[i]=p;
- for (j=0; j<=n-1; j++)
- { u=j*n+i; v=j*n+k;
- p=q[u]; q[u]=q[v]; q[v]=p;
- }
- }
- }
- return(1);
- }
#include "stdafx.h"
#include "math.h"
void cstrq(double a[],int n,double q[],double b[],double c[]);
int csstq(int n,double b[],double c[],double q[],double eps,int l);
int _tmain(int argc, _TCHAR* argv[])
{
int i,j,k,l=60;
static double b[5],c[5],q[25];
static double a[25] = {10.0,1.0,2.0,3.0,4.0,1.0,9.0,-1.0,2.0,-3.0,2.0,-1.0,7.0,3.0,-5.0,3.0,2.0,3.0,12.0,-1.0,4.0,-3.0,-5.0,-1.0,15.0};
double eps = 0.000001;
cstrq(a,5,q,b,c);
k = csstq(5,b,c,q,eps,l);
printf("MAT A is:\n");
for (i=0;i<5;i++)
{
for (j=0;j<5;j++)
{
printf("%13.7e ",a[i*5+j]);
}
printf("\n");
}
printf("\n");
printf("MAT B is:\n");
for (i=0;i<5;i++)
{
printf("%13.7e ",b[i]);
}
printf("\n\n");
printf("MAT Q is:\n");
for (i=0;i<5;i++)
{
for (j=0;j<5;j++)
{
printf("%13.7e ",q[i*5+j]);
}
printf("\n");
}
printf("\n");
return 0;
}
void cstrq(double a[],int n,double q[],double b[],double c[])
{
int i,j,k,u,v;
double h,f,g,h2;
for (i=0; i<=n-1; i++)
for (j=0; j<=n-1; j++)
{ u=i*n+j; q[u]=a[u];}
for (i=n-1; i>=1; i--)
{ h=0.0;
if (i>1)
for (k=0; k<=i-1; k++)
{ u=i*n+k; h=h+q[u]*q[u];}
if (h+1.0==1.0)
{ c[i]=0.0;
if (i==1) c[i]=q[i*n+i-1];
b[i]=0.0;
}
else
{ c[i]=sqrt(h);
u=i*n+i-1;
if (q[u]>0.0) c[i]=-c[i];
h=h-q[u]*c[i];
q[u]=q[u]-c[i];
f=0.0;
for (j=0; j<=i-1; j++)
{ q[j*n+i]=q[i*n+j]/h;
g=0.0;
for (k=0; k<=j; k++)
g=g+q[j*n+k]*q[i*n+k];
if (j+1<=i-1)
for (k=j+1; k<=i-1; k++)
g=g+q[k*n+j]*q[i*n+k];
c[j]=g/h;
f=f+g*q[j*n+i];
}
h2=f/(h+h);
for (j=0; j<=i-1; j++)
{ f=q[i*n+j];
g=c[j]-h2*f;
c[j]=g;
for (k=0; k<=j; k++)
{ u=j*n+k;
q[u]=q[u]-f*c[k]-g*q[i*n+k];
}
}
b[i]=h;
}
}
for (i=0; i<=n-2; i++) c[i]=c[i+1];
c[n-1]=0.0;
b[0]=0.0;
for (i=0; i<=n-1; i++)
{ if ((b[i]!=0.0)&&(i-1>=0))
for (j=0; j<=i-1; j++)
{ g=0.0;
for (k=0; k<=i-1; k++)
g=g+q[i*n+k]*q[k*n+j];
for (k=0; k<=i-1; k++)
{ u=k*n+j;
q[u]=q[u]-g*q[k*n+i];
}
}
u=i*n+i;
b[i]=q[u]; q[u]=1.0;
if (i-1>=0)
for (j=0; j<=i-1; j++)
{ q[i*n+j]=0.0; q[j*n+i]=0.0;}
}
return;
}
int csstq(int n,double b[],double c[],double q[],double eps,int l)
{
int i,j,k,m,it,u,v;
double d,f,h,g,p,r,e,s;
c[n-1]=0.0; d=0.0; f=0.0;
for (j=0; j<=n-1; j++)
{ it=0;
h=eps*(fabs(b[j])+fabs(c[j]));
if (h>d) d=h;
m=j;
while ((m<=n-1)&&(fabs(c[m])>d)) m=m+1;
if (m!=j)
{ do
{ if (it==l)
{ printf("fail\n");
return(-1);
}
it=it+1;
g=b[j];
p=(b[j+1]-g)/(2.0*c[j]);
r=sqrt(p*p+1.0);
if (p>=0.0) b[j]=c[j]/(p+r);
else b[j]=c[j]/(p-r);
h=g-b[j];
for (i=j+1; i<=n-1; i++)
b[i]=b[i]-h;
f=f+h; p=b[m]; e=1.0; s=0.0;
for (i=m-1; i>=j; i--)
{ g=e*c[i]; h=e*p;
if (fabs(p)>=fabs(c[i]))
{ e=c[i]/p; r=sqrt(e*e+1.0);
c[i+1]=s*p*r; s=e/r; e=1.0/r;
}
else
{ e=p/c[i]; r=sqrt(e*e+1.0);
c[i+1]=s*c[i]*r;
s=1.0/r; e=e/r;
}
p=e*b[i]-s*g;
b[i+1]=h+s*(e*g+s*b[i]);
for (k=0; k<=n-1; k++)
{ u=k*n+i+1; v=u-1;
h=q[u]; q[u]=s*q[v]+e*h;
q[v]=e*q[v]-s*h;
}
}
c[j]=s*p; b[j]=e*p;
}
while (fabs(c[j])>d);
}
b[j]=b[j]+f;
}
for (i=0; i<=n-1; i++)
{ k=i; p=b[i];
if (i+1<=n-1)
{ j=i+1;
while ((j<=n-1)&&(b[j]<=p))
{ k=j; p=b[j]; j=j+1;}
}
if (k!=i)
{ b[k]=b[i]; b[i]=p;
for (j=0; j<=n-1; j++)
{ u=j*n+i; v=j*n+k;
p=q[u]; q[u]=q[v]; q[v]=p;
}
}
}
return(1);
}
這裏,又把householder貼了一遍。。。
計算結果:
這裏,我們要注意:
數組q中第j列爲數組b中第j個特徵值對應的特徵向量
- 頂
- 5
- 踩
- 0
我的同類文章
- •Gauss-Newton算法學習2016-06-08
- •機器學習之旅---奇異值分解2014-11-22
- •機器學習之旅---logistic迴歸2014-10-12
- •離散隨機線性系統的卡爾曼濾波器基本原理及實現2014-06-13
- •SVM理論部分介紹2013-12-28
- •《Master Opencv...讀書筆記》非剛性人臉跟蹤 III2015-02-28
- •機器學習之旅---SVM分類器2014-11-07
- •機器學習之旅---樸素貝葉斯分類器2014-09-24
- •matlab體驗svm算法【非實現】2013-12-30