FastICA 步骤:
1. 对观测数据 X 进行中心化处理,使样本的每个属性均值为0
2. 求出样本矩阵的协方差矩阵 Cx
3. 用主成分分析得到白化矩阵 W0=Λ-1/2UT 对 其中Λ、U分别是Cx的特征值、特征向量
4. 计算正交阵Z=W0*X, Z维数可以根据主成分的占比,小于样本属性数
5. 初始化权重矩阵(随机的)Wp 、设迭代次数count、停机误差Critical
6. 令Wp=E{ Z*g(WTZ) } - E{ g'(WTZ) }*W 其中非线性函数g(x),可取g1(x)=tanh(x)或g2(y)=y*exp(-y2/2)或g3(y)=y3等非线性函数
7. SZ=Wp*Z 为分离后的信号矩阵
import matplotlib.pyplot as plt
import numpy as np
from numpy import linalg as LA
C=200 #样本数
x=np.arange(C)
s1=2*np.sin(0.02*np.pi *x)#正弦信号
a=np.linspace(-2,2,25)
s2= np.array([a,a,a,a,a,a,a,a]).reshape(200,)#锯齿信号
s3=np.array(20*(5*[2]+5*[-2])) #方波信号
s4 =4*(np.random.random([1,C])-0.5).reshape(200,) #随机信号
# drow origin signal
ax1 = plt.subplot(411)
ax2 = plt.subplot(412)
ax3 = plt.subplot(413)
ax4 = plt.subplot(414)
ax1.plot(x,s1)
ax2.plot(x,s2)
ax3.plot(x,s3)
ax4.plot(x,s4)
plt.show()
s=np.array([s1,s2,s3,s4]) #合成信号
ran=2*np.random.random([4,4]) #随机矩阵
mix=ran.dot(s) #混合信号
# drow mix signal
ax1 = plt.subplot(411)
ax2 = plt.subplot(412)
ax3 = plt.subplot(413)
ax4 = plt.subplot(414)
ax1.plot(x,mix.T[:,0])
ax2.plot(x,mix.T[:,1])
ax3.plot(x,mix.T[:,2])
ax4.plot(x,mix.T[:,3])
plt.show()
#mix=np.array([[1.1,2,3,4,1],
# [5,6,2,8,7],
# [6,2,5,1,3],
# [7,8,3,3,2]])
Maxcount=10000 # %最大迭代次数
Critical=0.00001 # %判断是否收敛
R,C=mix.shape
average=np.mean(mix, axis=1) #计算行均值,axis=0,计算每一列的均值
for i in range(R):
mix[i,:]=mix[i,:]- average[i] #数据标准化,均值为零
Cx=np.cov(mix)
value,eigvector = np.linalg.eig(Cx)#计算协方差阵的特征值
val=value**(-1/2)*np.eye(R, dtype=float)
White=np.dot(val ,eigvector.T) #白化矩阵
Z=np.dot(White,mix) #混合矩阵的主成分Z,Z为正交阵
#W = np.random.random((R,R))# 4x4
W=0.5*np.ones([4,4])#初始化权重矩阵
for n in range(R):
count=0
WP=W[:,n].reshape(R,1) #初始化
LastWP=np.zeros(R).reshape(R,1) # 列向量;LastWP=zeros(m,1);
while LA.norm(WP-LastWP,1)>Critical:
#print(count," loop :",LA.norm(WP-LastWP,1))
count=count+1
LastWP=np.copy(WP) # %上次迭代的值
gx=np.tanh(LastWP.T.dot(Z)) # 行向量
for i in range(R):
tm1=np.mean( Z[i,:]*gx )
tm2=np.mean(1-gx**2)*LastWP[i] #收敛快
#tm2=np.mean(gx)*LastWP[i] #收敛慢
WP[i]=tm1 - tm2
#print(" wp :", WP.T )
WPP=np.zeros(R) #一维0向量
for j in range(n):
WPP=WPP+ WP.T.dot(W[:,j])* W[:,j]
WP.shape=1,R
WP=WP-WPP
WP.shape=R,1
WP=WP/(LA.norm(WP))
if(count ==Maxcount):
print("reach Maxcount,exit loop",LA.norm(WP-LastWP,1))
break
print("loop count:",count )
W[:,n]=WP.reshape(R,)
SZ=W.T.dot(Z)
# plot extract signal
x=np.arange(0,C)
ax1 = plt.subplot(411)
ax2 = plt.subplot(412)
ax3 = plt.subplot(413)
ax4 = plt.subplot(414)
ax1.plot(x, SZ.T[:,0])
ax2.plot(x, SZ.T[:,1])
ax3.plot(x, SZ.T[:,2])
ax4.plot(x, SZ.T[:,3])
plt.show()
结果示意图:
下面为C++代码实现,和python有相同的结果。
#include "matrix.h"
/*
数据格式:行数是属性数,每一列是一个样本,一下为实例数据
1.1 2 3 4 1
5 6 2 8 7
6 2 5 1 3
7 8 3 3 2
*/
int main()
{
int R = 4;
int C = 5;
int maxcnt= 200;
Matrix src(R, C); // 原始数据
cin >> src;
src.zeromean(false);
Matrix Cov = src.T().cov(); //样本的协方差矩阵
Matrix eigval = Cov.eig_val();
cout << "eigval \n" << eigval << endl;
Matrix eigvect = Cov.eig_vect();
cout << "eigvect \n" << eigvect << endl;
eigval = eigval.exponent(-0.5);//每个特征值的 -0.5 次方
eigval.maxlimit(10000); ///超过10000,设置为0
cout << "eigval^-0.5 \n" << eigval;
Matrix white = eigval* eigvect.T(); //由特征值、特征向量组成白化矩阵
Matrix Z = white*src; //正交阵
cout << "Z:\n" << Z;
Matrix W(R, R, 0.5); //初始权值矩阵
for (size_t i = 0; i < R; i++)
{
int cnt = 0;
Matrix WP = W.getcol(i);
Matrix LastWP(R,1,0);
while ((WP - LastWP).norm1()>0.01)
{
cnt++;
LastWP = WP; //上次迭代的值
Matrix gx = (LastWP.T()*Z).mtanh();// 行向量
for (size_t j = 0; j < R; j++) //更新 WP
{
double tm1 = (Z.getrow(j).multi(gx) ).mean();
Matrix one(gx.Row(), gx.Col(), 1.0);
double tm2 = (one - gx.exponent(2)).mean()*LastWP[j][0];
WP[j][0] = tm1 - tm2;
}
Matrix WPP(R, 1, 0);
for (size_t k = 0; k < i; k++)
{
double tem = (WP.T()*W.getcol(k))[0][0];
WPP = WPP + tem * W.getcol(k);
}
WP = WP - WPP;
WP = WP / (WP.norm2());
if (cnt == maxcnt)
{
cout << "reach Maxcount:"<< maxcnt<<",exit loop" << endl;
break;
}
}
cout << "loop cnt:" << cnt << endl;
for (size_t s = 0; s < R; s++)
{
W[s][i] = WP[s][0];
}
}
cout << "W:\n" << W << endl;
Matrix SZ = W.T()*Z;
cout << "SZ:\n" << SZ<<endl;
system("pause");
}
测试数据的结果为:
与python结果对比:
参考文献:
1,https://en.wikipedia.org/wiki/Independent_component_analysis
2,https://blog.csdn.net/zb1165048017/article/details/48464573
c++引用的矩阵类Matrix.h
#include<iostream>
#include <fstream> // std::ifstream
#include <stdlib.h>
#include <cmath>
using namespace std;
class Matrix
{
private:
unsigned row, col, size;
double *pmm;//数组指针
public:
Matrix(unsigned r, unsigned c) :row(r), col(c)//非方阵构造
{
size = r*c;
if (size>0)
{
pmm = new double[size];
for (unsigned j = 0; j<size; j++) //init
{
pmm[j] = 0.0;
}
}
else
pmm = NULL;
};
Matrix(unsigned r, unsigned c, double val ) :row(r), col(c)// 赋初值val
{
size = r*c;
if (size>0)
{
pmm = new double[size];
for (unsigned j = 0; j<size; j++) //init
{
pmm[j] = val;
}
}
else
pmm = NULL;
};
Matrix(unsigned n) :row(n), col(n)//方阵构造
{
size = n*n;
if (size>0)
{
pmm = new double[size];
for (unsigned j = 0; j<size; j++) //init
{
pmm[j] = 0.0;
}
}
else
pmm = NULL;
};
Matrix(const Matrix &rhs)//拷贝构造
{
row = rhs.row;
col = rhs.col;
size = rhs.size;
pmm = new double[size];
for (unsigned i = 0; i<size; i++)
pmm[i] = rhs.pmm[i];
}
~Matrix()//析构
{
if (pmm != NULL)
{
delete[]pmm;
pmm = NULL;
}
}
Matrix &operator=(const Matrix&); //如果类成员有指针必须重写赋值运算符,必须是成员
friend istream &operator>>(istream&, Matrix&);
friend ofstream &operator<<(ofstream &out, Matrix &obj); // 输出到文件
friend ostream &operator<<(ostream&, Matrix&); // 输出到屏幕
friend Matrix operator+(const Matrix&, const Matrix&);
friend Matrix operator-(const Matrix&, const Matrix&);
friend Matrix operator*(const Matrix&, const Matrix&); //矩阵乘法
friend Matrix operator*(double, const Matrix&); //矩阵乘法
friend Matrix operator*(const Matrix&, double); //矩阵乘法
friend Matrix operator/(const Matrix&, double); //矩阵 除以单数
Matrix multi(const Matrix&); // 对应元素相乘
Matrix mtanh(); // 对应元素相乘
unsigned Row()const{ return row; }
unsigned Col()const{ return col; }
Matrix getrow(size_t index); // 返回第index 行,索引从0 算起
Matrix getcol(size_t index); // 返回第index 列
Matrix cov(_In_opt_ bool flag = true); //协方差阵 或者样本方差
double det(); //行列式
Matrix solveAb(Matrix &obj); // b是行向量或者列向量
Matrix diag(); //返回对角线元素
//Matrix asigndiag(); //对角线元素
Matrix T()const; //转置
void sort(bool);//true为从小到大
Matrix adjoint();
Matrix inverse();
void QR(_Out_ Matrix&, _Out_ Matrix&)const;
Matrix eig_val(_In_opt_ unsigned _iters = 1000);
Matrix eig_vect(_In_opt_ unsigned _iters = 1000);
double norm1();//1范数
double norm2();//2范数
double mean();// 矩阵均值
double*operator[](int i){ return pmm + i*col; }//注意this加括号, (*this)[i][j]
void zeromean(_In_opt_ bool flag = true);//默认参数为true计算列
void normalize(_In_opt_ bool flag = true);//默认参数为true计算列
Matrix exponent(double x);//每个元素x次幂
Matrix eye();//对角阵
void maxlimit(double max,double set=0);//对角阵
};
//友元仅仅是指定了访问权限,不是一般意义的函数声明,最好在类外再进行一次函数声明。
//istream &operator>>(istream &is, Matrix &obj);
//ostream &operator<<(ostream &is, Matrix &obj);
//对称性运算符,如算术,相等,应该是普通非成员函数。
//Matrix operator*( const Matrix&,const Matrix& );
//Matrix operator+( const Matrix&,const Matrix& );
//dets递归调用
Matrix Matrix::mtanh() // 对应元素 tanh()
{
Matrix ret(row, col);
for (unsigned i = 0; i<ret.size; i++)
{
ret.pmm[i] = tanh(pmm[i]);
}
return ret;
}
double dets(int n, double *&aa)
{
if (n == 1)
return aa[0];
double *bb = new double[(n - 1)*(n - 1)];//创建n-1阶的代数余子式阵bb
int mov = 0;//判断行是否移动
double sum = 0.0;//sum为行列式的值
for (int arow = 0; arow<n; arow++) // a的行数把矩阵a(nn)赋值到b(n-1)
{
for (int brow = 0; brow<n - 1; brow++)//把aa阵第一列各元素的代数余子式存到bb
{
mov = arow > brow ? 0 : 1; //bb中小于arow的行,同行赋值,等于的错过,大于的加一
for (int j = 0; j<n - 1; j++) //从aa的第二列赋值到第n列
{
bb[brow*(n - 1) + j] = aa[(brow + mov)*n + j + 1];
}
}
int flag = (arow % 2 == 0 ? 1 : -1);//因为列数为0,所以行数是偶数时候,代数余子式为1.
sum += flag* aa[arow*n] * dets(n - 1, bb);//aa第一列各元素与其代数余子式积的和即为行列式
}
delete[]bb;
return sum;
}
Matrix Matrix::solveAb(Matrix &obj)
{
Matrix ret(row, 1);
if (size == 0 || obj.size == 0)
{
cout << "solveAb(Matrix &obj):this or obj is null" << endl;
return ret;
}
if (row != obj.size)
{
cout << "solveAb(Matrix &obj):the row of two matrix is not equal!" << endl;
return ret;
}
double *Dx = new double[row*row];
for (int i = 0; i<row; i++)
{
for (int j = 0; j<row; j++)
{
Dx[i*row + j] = pmm[i*row + j];
}
}
double D = dets(row, Dx);
if (D == 0)
{
cout << "Cramer法则只能计算系数矩阵为满秩的矩阵" << endl;
return ret;
}
for (int j = 0; j<row; j++)
{
for (int i = 0; i<row; i++)
{
for (int j = 0; j<row; j++)
{
Dx[i*row + j] = pmm[i*row + j];
}
}
for (int i = 0; i<row; i++)
{
Dx[i*row + j] = obj.pmm[i]; //obj赋值给第j列
}
//for( int i=0;i<row;i++) //print
//{
// for(int j=0; j<row;j++)
// {
// cout<< Dx[i*row+j]<<"\t";
// }
// cout<<endl;
//}
ret[j][0] = dets(row, Dx) / D;
}
delete[]Dx;
return ret;
}
Matrix Matrix::getrow(size_t index)//返回行
{
Matrix ret(1, col); //一行的返回值
for (unsigned i = 0; i< col; i++)
{
ret[0][i] = pmm[(index) *col + i] ;
}
return ret;
}
Matrix Matrix::getcol(size_t index)//返回列
{
Matrix ret(row, 1); //一列的返回值
for (unsigned i = 0; i< row; i++)
{
ret[i][0] = pmm[i *col + index];
}
return ret;
}
Matrix Matrix::exponent(double x)//每个元素x次幂
{
Matrix ret(row, col);
double a;
for (unsigned i = 0; i< row; i++)
{
for (unsigned j = 0; j < col; j++)
{
a=ret[i][j]= pow(pmm[i*col + j],x);
}
}
return ret;
}
void Matrix::maxlimit(double max, double set)//每个元素x次幂
{
for (unsigned i = 0; i< row; i++)
{
for (unsigned j = 0; j < col; j++)
{
pmm[i*col + j] = pmm[i*col + j]>max ? 0 : pmm[i*col + j];
}
}
}
Matrix Matrix::eye()//对角阵
{
for (unsigned i = 0; i< row; i++)
{
for (unsigned j = 0; j < col; j++)
{
if (i == j)
{
pmm[i*col + j] = 1.0;
}
}
}
return *this;
}
void Matrix::zeromean(_In_opt_ bool flag)
{
if (flag == true) //计算列均值
{
double *mean = new double[col];
for (unsigned j = 0; j < col; j++)
{
mean[j] = 0.0;
for (unsigned i = 0; i < row; i++)
{
mean[j] += pmm[i*col + j];
}
mean[j] /= row;
}
for (unsigned j = 0; j < col; j++)
{
for (unsigned i = 0; i < row; i++)
{
pmm[i*col + j] -= mean[j];
}
}
delete[]mean;
}
else //计算行均值
{
double *mean = new double[row];
for (unsigned i = 0; i< row; i++)
{
mean[i] = 0.0;
for (unsigned j = 0; j < col; j++)
{
mean[i] += pmm[i*col + j];
}
mean[i] /= col;
}
for (unsigned i = 0; i < row; i++)
{
for (unsigned j = 0; j < col; j++)
{
pmm[i*col + j] -= mean[i];
}
}
delete[]mean;
}
}
void Matrix::normalize(_In_opt_ bool flag)
{
if (flag == true) //计算列均值
{
double *mean = new double[col];
for (unsigned j = 0; j < col; j++)
{
mean[j] = 0.0;
for (unsigned i = 0; i < row; i++)
{
mean[j] += pmm[i*col + j];
}
mean[j] /= row;
}
for (unsigned j = 0; j < col; j++)
{
for (unsigned i = 0; i < row; i++)
{
pmm[i*col + j] -= mean[j];
}
}
///计算标准差
for (unsigned j = 0; j < col; j++)
{
mean[j] = 0;
for (unsigned i = 0; i < row; i++)
{
mean[j] += pow(pmm[i*col + j],2);//列平方和
}
mean[j] = sqrt(mean[j] / row); // 开方
}
for (unsigned j = 0; j < col; j++)
{
for (unsigned i = 0; i < row; i++)
{
pmm[i*col + j] /= mean[j];//列平方和
}
}
delete[]mean;
}
else //计算行均值
{
double *mean = new double[row];
for (unsigned i = 0; i< row; i++)
{
mean[i] = 0.0;
for (unsigned j = 0; j < col; j++)
{
mean[i] += pmm[i*col + j];
}
mean[i] /= col;
}
for (unsigned i = 0; i < row; i++)
{
for (unsigned j = 0; j < col; j++)
{
pmm[i*col + j] -= mean[i];
}
}
///计算标准差
for (unsigned i = 0; i< row; i++)
{
mean[i] = 0.0;
for (unsigned j = 0; j < col; j++)
{
mean[i] += pow(pmm[i*col + j], 2);//列平方和
}
mean[i] = sqrt(mean[i] / col); // 开方
}
for (unsigned i = 0; i < row; i++)
{
for (unsigned j = 0; j < col; j++)
{
pmm[i*col + j] /= mean[i];
}
}
delete[]mean;
}
}
double Matrix::det()
{
if (col == row)
return dets(row, pmm);
else
{
cout << ("行列不相等无法计算") << endl;
return 0;
}
}
/
istream &operator>>(istream &is, Matrix &obj)
{
for (unsigned i = 0; i<obj.size; i++)
{
is >> obj.pmm[i];
}
return is;
}
ostream &operator<<(ostream &out, Matrix &obj)
{
for (unsigned i = 0; i < obj.row; i++) //打印逆矩阵
{
for (unsigned j = 0; j < obj.col; j++)
{
out << (obj[i][j]) << "\t";
}
out << endl;
}
return out;
}
ofstream &operator<<(ofstream &out, Matrix &obj)//打印逆矩阵到文件
{
for (unsigned i = 0; i < obj.row; i++)
{
for (unsigned j = 0; j < obj.col; j++)
{
out << (obj[i][j]) << "\t";
}
out << endl;
}
return out;
}
Matrix operator+(const Matrix& lm, const Matrix& rm)
{
if (lm.col != rm.col || lm.row != rm.row)
{
Matrix temp(0, 0);
temp.pmm = NULL;
cout << "operator+(): 矩阵shape 不合适,col:"
<< lm.col << "," << rm.col << ". row:" << lm.row << ", " << rm.row << endl;
return temp; //数据不合法时候,返回空矩阵
}
Matrix ret(lm.row, lm.col);
for (unsigned i = 0; i<ret.size; i++)
{
ret.pmm[i] = lm.pmm[i] + rm.pmm[i];
}
return ret;
}
Matrix operator-(const Matrix& lm, const Matrix& rm)
{
if (lm.col != rm.col || lm.row != rm.row)
{
Matrix temp(0, 0);
temp.pmm = NULL;
cout << "operator-(): 矩阵shape 不合适,col:"
<<lm.col<<","<<rm.col<<". row:"<< lm.row <<", "<< rm.row << endl;
return temp; //数据不合法时候,返回空矩阵
}
Matrix ret(lm.row, lm.col);
for (unsigned i = 0; i<ret.size; i++)
{
ret.pmm[i] = lm.pmm[i] - rm.pmm[i];
}
return ret;
}
Matrix operator*(const Matrix& lm, const Matrix& rm) //矩阵乘法
{
if (lm.size == 0 || rm.size == 0 || lm.col != rm.row)
{
Matrix temp(0, 0);
temp.pmm = NULL;
cout << "operator*(): 矩阵shape 不合适,col:"
<< lm.col << "," << rm.col << ". row:" << lm.row << ", " << rm.row << endl;
return temp; //数据不合法时候,返回空矩阵
}
Matrix ret(lm.row, rm.col);
for (unsigned i = 0; i<lm.row; i++)
{
for (unsigned j = 0; j< rm.col; j++)
{
for (unsigned k = 0; k< lm.col; k++)//lm.col == rm.row
{
ret.pmm[i*rm.col + j] += lm.pmm[i*lm.col + k] * rm.pmm[k*rm.col + j];
}
}
}
return ret;
}
Matrix operator*(double val, const Matrix& rm) //矩阵乘 单数
{
Matrix ret(rm.row, rm.col);
for (unsigned i = 0; i<ret.size; i++)
{
ret.pmm[i] = val * rm.pmm[i];
}
return ret;
}
Matrix operator*(const Matrix&lm, double val) //矩阵乘 单数
{
Matrix ret(lm.row, lm.col);
for (unsigned i = 0; i<ret.size; i++)
{
ret.pmm[i] = val * lm.pmm[i];
}
return ret;
}
Matrix operator/(const Matrix&lm, double val) //矩阵除以 单数
{
Matrix ret(lm.row, lm.col);
for (unsigned i = 0; i<ret.size; i++)
{
ret.pmm[i] = lm.pmm[i]/val;
}
return ret;
}
Matrix Matrix::multi(const Matrix&rm)// 对应元素相乘
{
if (col != rm.col || row != rm.row)
{
Matrix temp(0, 0);
temp.pmm = NULL;
cout << "multi(const Matrix&rm): 矩阵shape 不合适,col:"
<< col << "," << rm.col << ". row:" << row << ", " << rm.row << endl;
return temp; //数据不合法时候,返回空矩阵
}
Matrix ret(row,col);
for (unsigned i = 0; i<ret.size; i++)
{
ret.pmm[i] = pmm[i] * rm.pmm[i];
}
return ret;
}
Matrix& Matrix::operator=(const Matrix& rhs)
{
if (this != &rhs)
{
row = rhs.row;
col = rhs.col;
size = rhs.size;
if (pmm != NULL)
delete[] pmm;
pmm = new double[size];
for (unsigned i = 0; i<size; i++)
{
pmm[i] = rhs.pmm[i];
}
}
return *this;
}
//||matrix||_2 求A矩阵的2范数
double Matrix::norm2()
{
double norm = 0;
for (unsigned i = 0; i < size; ++i)
{
norm += pmm[i] * pmm[i];
}
return (double)sqrt(norm);
}
double Matrix::norm1()
{
double sum = 0;
for (unsigned i = 0; i < size; ++i)
{
sum += abs(pmm[i]);
}
return sum;
}
double Matrix::mean()
{
double sum = 0;
for (unsigned i = 0; i < size; ++i)
{
sum += (pmm[i]);
}
return sum/size;
}
void Matrix::sort(bool flag)
{
double tem;
for (unsigned i = 0; i<size; i++)
{
for (unsigned j = i + 1; j<size; j++)
{
if (flag == true)
{
if (pmm[i]>pmm[j])
{
tem = pmm[i];
pmm[i] = pmm[j];
pmm[j] = tem;
}
}
else
{
if (pmm[i]<pmm[j])
{
tem = pmm[i];
pmm[i] = pmm[j];
pmm[j] = tem;
}
}
}
}
}
Matrix Matrix::diag()
{
if (row != col)
{
Matrix m(0);
cout << "diag():row != col" << endl;
return m;
}
Matrix m(row);
for (unsigned i = 0; i<row; i++)
{
m.pmm[i*row + i] = pmm[i*row + i];
}
return m;
}
Matrix Matrix::T()const
{
Matrix tem(col, row);
for (unsigned i = 0; i<row; i++)
{
for (unsigned j = 0; j<col; j++)
{
tem[j][i] = pmm[i*col + j];// (*this)[i][j]
}
}
return tem;
}
void Matrix::QR(Matrix &Q, Matrix &R) const
{
//如果A不是一个二维方阵,则提示错误,函数计算结束
if (row != col)
{
printf("ERROE: QR() parameter A is not a square matrix!\n");
return;
}
const unsigned N = row;
double *a = new double[N];
double *b = new double[N];
for (unsigned j = 0; j < N; ++j) //(Gram-Schmidt) 正交化方法
{
for (unsigned i = 0; i < N; ++i) //第j列的数据存到a,b
a[i] = b[i] = pmm[i * N + j];
for (unsigned i = 0; i<j; ++i) //第j列之前的列
{
R.pmm[i * N + j] = 0; //
for (unsigned m = 0; m < N; ++m)
{
R.pmm[i * N + j] += a[m] * Q.pmm[m *N + i]; //R[i,j]值为Q第i列与A的j列的内积
}
for (unsigned m = 0; m < N; ++m)
{
b[m] -= R.pmm[i * N + j] * Q.pmm[m * N + i]; //
}
}
double norm = 0;
for (unsigned i = 0; i < N; ++i)
{
norm += b[i] * b[i];
}
norm = (double)sqrt(norm);
R.pmm[j*N + j] = norm; //向量b[]的2范数存到R[j,j]
for (unsigned i = 0; i < N; ++i)
{
Q.pmm[i * N + j] = b[i] / norm; //Q 阵的第j列为单位化的b[]
}
}
delete[]a;
delete[]b;
}
Matrix Matrix::eig_val(_In_opt_ unsigned _iters)
{
if (size == 0 || row != col)
{
cout << "矩阵为空或者非方阵!" << endl;
Matrix rets(0);
return rets;
}
//if (det() == 0)
//{
// cout << "非满秩矩阵没法用QR分解计算特征值!" << endl;
// Matrix rets(0);
// return rets;
//}
const unsigned N = row;
Matrix matcopy(*this);//备份矩阵
Matrix Q(N), R(N);
/*当迭代次数足够多时,A 趋于上三角矩阵,上三角矩阵的对角元就是A的全部特征值。*/
for (unsigned k = 0; k < _iters; ++k)
{
//cout<<"this:\n"<<*this<<endl;
QR(Q, R);
*this = R*Q;
/* cout<<"Q:\n"<<Q<<endl;
cout<<"R:\n"<<R<<endl; */
}
Matrix val = diag();
*this = matcopy;//恢复原始矩阵;
return val;
}
Matrix Matrix::eig_vect(_In_opt_ unsigned _iters)
{
if (size == 0 || row != col)
{
cout << "矩阵为空或者非方阵!" << endl;
Matrix rets(0);
return rets;
}
if (det() == 0)
{
cout << "非满秩矩阵没法用QR分解计算特征向量!" << endl;
Matrix rets(0);
return rets;
}
Matrix matcopy(*this);//备份矩阵
Matrix eigenValue = eig_val(_iters);
Matrix ret(row);
const unsigned NUM = col;
double eValue;
double sum, midSum, diag;
Matrix copym(*this);
for (unsigned count = 0; count < NUM; ++count)
{
//计算特征值为eValue,求解特征向量时的系数矩阵
*this = copym;
eValue = eigenValue[count][count];
for (unsigned i = 0; i < col; ++i)//A-lambda*I
{
pmm[i * col + i] -= eValue;
}
//cout<<*this<<endl;
//将 this为阶梯型的上三角矩阵
for (unsigned i = 0; i < row - 1; ++i)
{
diag = pmm[i*col + i]; //提取对角元素
for (unsigned j = i; j < col; ++j)
{
pmm[i*col + j] /= diag; //【i,i】元素变为1
}
for (unsigned j = i + 1; j<row; ++j)
{
diag = pmm[j * col + i];
for (unsigned q = i; q < col; ++q)//消去第i+1行的第i个元素
{
pmm[j*col + q] -= diag*pmm[i*col + q];
}
}
}
//cout<<*this<<endl;
//特征向量最后一行元素置为1
midSum = ret.pmm[(ret.row - 1) * ret.col + count] = 1;
for (int m = row - 2; m >= 0; --m)
{
sum = 0;
for (unsigned j = m + 1; j < col; ++j)
{
sum += pmm[m * col + j] * ret.pmm[j * ret.col + count];
}
sum = -sum / pmm[m * col + m];
midSum += sum * sum;
ret.pmm[m * ret.col + count] = sum;
}
midSum = sqrt(midSum);
for (unsigned i = 0; i < ret.row; ++i)
{
ret.pmm[i * ret.col + count] /= midSum; //每次求出一个列向量
}
}
*this = matcopy;//恢复原始矩阵;
return ret;
}
Matrix Matrix::cov(bool flag)
{
//row 样本数,column 变量数
if (col == 0)
{
Matrix m(0);
return m;
}
double *mean = new double[col]; //均值向量
for (unsigned j = 0; j<col; j++) //init
{
mean[j] = 0.0;
}
Matrix ret(col);
for (unsigned j = 0; j<col; j++) //mean
{
for (unsigned i = 0; i<row; i++)
{
mean[j] += pmm[i*col + j];
}
mean[j] /= row;
}
unsigned i, k, j;
for (i = 0; i<col; i++) //第一个变量
{
for (j = i; j<col; j++) //第二个变量
{
for (k = 0; k<row; k++) //计算
{
ret[i][j] += (pmm[k*col + i] - mean[i])*(pmm[k*col + j] - mean[j]);
}
if (flag == true)
{
ret[i][j] /= (row-1);
}
else
{
ret[i][j] /= (row);
}
/*temp.Format("cov=%f,column=%d mean(%d)=%f,mean(%d)=%f",cov[i*column+j],row,i,mean[i],j,mean[j]);
MessageBox(temp);*/
}
}
for (i = 0; i<col; i++) //补全对应面
{
for (j = 0; j<i; j++)
{
ret[i][j] = ret[j][i];
}
}
return ret;
}
Matrix Matrix::adjoint()
{
//调动之前,检查时候方阵,这里默认为aa为方阵
//确定本函数是否修改传入的数据 :no
//调用函数内删除内存delete []padjoint;
if (row != col)
{
Matrix ret(0);
return ret;
}
const int n = row;
Matrix ret(row);
double *bb = new double[(n - 1)*(n - 1)];//创建n-1阶的代数余子式阵bb
int pi, pj, q;
for (int ai = 0; ai<n; ai++) // a的行数把矩阵a(nn)赋值到b(n-1)
{
for (int aj = 0; aj<n; aj++)
{
for (int bi = 0; bi<n - 1; bi++)//把元素aa[ai][0]余子式存到bb[][]
{
for (int bj = 0; bj<n - 1; bj++)//把元素aa[ai][0]代数余子式存到bb[][]
{
if (ai>bi) //ai行的代数余子式是:小于ai的行,aa与bb阵,同行赋值
pi = 0;
else
pi = 1; //大于等于ai的行,取aa阵的ai+1行赋值给阵bb的bi行
if (aj>bj) //ai行的代数余子式是:小于ai的行,aa与bb阵,同行赋值
pj = 0;
else
pj = 1; //大于等于ai的行,取aa阵的ai+1行赋值给阵bb的bi行
bb[bi*(n - 1) + bj] = pmm[(bi + pi)*n + bj + pj];
}
}
if ((ai + aj) % 2 == 0) q = 1;//因为列数为0,所以行数是偶数时候,代数余子式为-1.
else q = (-1);
ret.pmm[ai*n + aj] = q*dets(n - 1, bb); //加符号变为代数余子式
}
}
delete[]bb;
return ret;
}
Matrix Matrix::inverse()
{
double det_aa = det();
if (det_aa == 0)
{
cout << "行列式为0 ,不能计算逆矩阵。" << endl;
Matrix rets(0);
return rets;
}
Matrix adj = adjoint();
Matrix ret(row);
for (unsigned i = 0; i<row; i++) //print
{
for (unsigned j = 0; j<col; j++)
{
ret.pmm[i*col + j] = adj.pmm[i*col + j] / det_aa;
}
}
return ret;
}