LDA 中文名称线性判别分析
最近用到LDA,因为不是数学方面出生,所以只管结果正确,不太追究具体的原理,在网上找到了一些别人的实现以及参考资料,自己实现了以下,但和OpenCV里面的LDA[1]结果相差较大,后来经过参考多个版本以及理论知识,最终实现版本如下,与OpenCV的LDA结果一致且与LDA的公式相符:
function [coeff, latent]= myLDA(data, labels)
% Make sure labels are nice
[classes, bar, labels] = unique(labels);
nc = length(classes);
dataMean = mean(data, 1);
Sb = 0;%类间
for i = 1:nc
cur_X = data(labels == i,:);
meanTemp = mean(cur_X, 1);
Sb = Sb + size(cur_X,1)*(meanTemp'-dataMean')*(meanTemp'-dataMean')';
end
Sw = 0;%类内
for i = 1:nc
cur_X = data(labels == i,:);
meanTemp = mean(cur_X, 1);
for j = 1:size(cur_X,1)
dataTemp = cur_X(j, :);
Sw = Sw + (meanTemp' - dataTemp')*(meanTemp' - dataTemp')';
end
end
Sb(isnan(Sb)) = 0; Sw(isnan(Sw)) = 0;
Sb(isinf(Sb)) = 0; Sw(isinf(Sw)) = 0;
[coeff, latent] = eig(Sw\Sb);
% Sort eigenvalues and eigenvectors in descending order
latent(isnan(latent)) = 0;
[latent, ind] = sort(diag(latent), 'descend');
[classes, ~, ~] = unique(labels);
no_dims = length(classes) - 1;
coeff = coeff(:,ind(1:min([no_dims size(coeff, 2)])));
end
测试数据1
data1 =
2.9500 6.6300
2.5300 7.7900
3.5700 5.6500
3.1600 5.4700<pre name="code" class="html"> 2.5800 4.4600
2.1600 6.2200
3.2700 3.5200
</pre><pre name="code" class="html"><pre name="code" class="html">label1 =
0
0
0
0
1
1
1
结果如下: [因为LDA主要用特征向量,故此处只给出特征向量的结果,特征值在不同的实现当中会各有不同]
coeff =
-0.9231
-0.3846
测试数据2
data2 =
0 1
0 2
2 4
8 0
8 2
9 4<pre name="code" class="html">label2 =
0
0
0
1
1
1
结果如下:
coeff =
0.9204
-0.3909
另外在matlab里面有一个专门做数据降维的工具箱drtoobox,里面有实现LDA,但感觉它的计算结果不是我想要的那种,但如果修改了当中的一些代码,计算结果就会与我的一致,主要是最后计算特征值和特征向量,在drtoolbox当中为:
[M, lambda] = eig(Sb, Sw);
改成以下则特征向量与我的一致:
[M, lambda] = eig(Sw\Sb);
理论上两种计算应该都可以,但根据LDA的具体公式[3],个人更倾向于第二种方式。
另外由于matlab当中目前实现了PCA,会与drtoolbox当中的pca函数名冲突,在使用这个toolbox的时候需要修改其函数名,并修改compute_mapping里面用到pca函数的地方。
此处给出drtoolbox的介绍和官网:
[1] 数据降维工具箱drtoolbox
[2] 官网: Matlab Toolbox for Dimensionality Reduction
参考文章:
[1] OpenCV LDA(Linnear Discriminant analysis)类的使用---OpenCV LDA示例
[2] 线性判别分析(Linear Discriminant Analysis, LDA)算法分析
[3] 《模式分类》 机械工业出版社P96 - P101