关于Matlab的讨论很多,这里我们不讨论具体的API细节,而是集中于高效使用Matlab这一主题,因此本文假设读者已经有了matlab的基本知识(本文不会对API的接口进行专门介绍,这部分可以通过matlab的help文档来解决),并且已经使用matlab一段时间。不能免俗的,本文被命名为Effective Matlab(向Effective C++致敬)。
Matlab对矩阵运算进行了深度优化,因此对于Matlab程序,矩阵操作的效率高于for循环。
需要指出的是,通过repmat将for循环转为矩阵运算会增加内存消耗,这种技巧的另外一个名字叫“空间换时间”。
x=-5 : .01 : 5;
y=x;
[X,Y] = meshgrid(x,y);
Z = X .* exp(-X.^2 - Y.^2);
1.1 使用repmat
repmat的作用在于对矩阵进行复制,通过repmat,我们可以将一部分for循环改写为矩阵运算,例如
以下函数实现了对数据的“均值归零,方差归一”。
function M = ZeroMeanOneVar(X,x_mean,x_var)
index = x_var<0.0000001;
x_var(index) = 1;
% x_mean(index) = 0;
num = size(X,2);
X_mean = repmat(x_mean, 1, num); %复制x_mean为1行num列
M = X - X_mean;
clear X_mean;
X_var = repmat(x_var, 1, num);
M = M ./ X_var;
clear X_var;
flag = isnan(M);
M(flag) = 0;
end
需要指出的是,通过repmat将for循环转为矩阵运算会增加内存消耗,这种技巧的另外一个名字叫“空间换时间”。
1.2 使用meshgrid
meshgrid的作用在于生成2维或者3维网格,例如我们需要绘制Z = x*exp(-x^2 - y^2), x和y的取值范围均为
[-5, 5]。
x=-5 : .01 : 5;
y=x;
[X,Y] = meshgrid(x,y);
Z = X .* exp(-X.^2 - Y.^2);
mesh(X,Y,Z)
x=-5 : .01 : 5;
y=x;
[X,Y] = meshgrid(x,y);
Z = X .* exp(-X.^2 - Y.^2);
mesh(X,Y,Z)
2. 考虑数值稳定性
2.1 用SVD代替eig
矩阵运算必须时刻牢记数值稳定性,例如eig()运算的数值稳定性不如SVD(), 而求特征值和特征向量对于机器学习中的常见算法PCA来说是必须的,下面展示了一个在PCA算法中应用SVD代替eig的例子。
% x_poa已经经过减均值操作
St = X_pca * X_pca';
[Vt Dt v] = svd(St);
eig_value_unsort = diag(Dt);
[eig_value eig_index] = sort(eig_value_unsort, 'descend' );
energy = sum(eig_value);
for i=1:dim
kept_energy = sum(eig_value(1:i));
if kept_energy > energy*0.98
fprintf( '%d dims can preserve 0.98 energy' ,i);
break ;
end
end
W_pca = zeros(dim,pca_dim); %W_pca????????????????
for i = 1:pca_dim
W_pca(:, i) = Vt(:,eig_index(i));
end
2.2 左除和右除
在matlab中,如果有以下操作:
Inv(A)*B, 建议用左除A\B代替。
A*Inv(B), 建议用右除A/B代替。
A右除B,相当于A右乘B的逆矩阵,A左除B,相当于A的逆矩阵左乘B