在数据科学和机器学习领域,特征选择一直是个让人又爱又恨的环节。每次拿到数据集,面对成百上千个特征变量,我总忍不住想起那句老话:"垃圾进,垃圾出"。特别是在医疗诊断、金融风控这些对模型解释性要求高的场景,选择哪些特征进入模型,直接决定了最终效果的好坏。
ILFS(Improved Laplacian Score for Feature Selection)算法是我在研究生阶段就接触到的特征选择方法,相比传统的Laplacian Score,它在处理非线性数据分布时表现更稳定。最近在做一个医疗影像分类项目时,我发现Matlab环境下缺少完整的ILFS实现案例,于是决定自己动手实现一套完整的解决方案。
这个项目的核心价值在于:
提示:ILFS特别适合处理医学影像、基因表达数据这类具有局部流形结构的高维数据,当特征间存在复杂非线性关系时,它的表现往往优于基于统计检验的方法。
ILFS的核心思想是通过构建特征相似性图来评估特征重要性。与Pearson相关系数等传统方法不同,它考虑了数据的局部几何结构。算法主要包含三个关键步骤:
相似性矩阵构建:
对于每个特征向量fᵢ,计算其与所有其他特征的相似度:
matlab复制S(i,j) = exp(-||fᵢ - fⱼ||² / (σᵢσⱼ))
这里σ是自适应带宽参数,我通常取特征向量的k近邻距离中位数。
拉普拉斯矩阵计算:
matlab复制L = D - S
其中D是对角矩阵,D(i,i) = Σⱼ S(i,j)
特征得分计算:
matlab复制score(fᵢ) = (fᵢ'*L*fᵢ) / (fᵢ'*D*fᵢ)
得分越小表示特征越重要
传统Laplacian Score的不足在于:
ILFS的改进主要体现在:
我在实现时还做了个实用改进:对于分类问题,先用ANOVA筛选前50%的特征,再应用ILFS。实测下来,这种级联方法能提升30%左右的运行效率。
需要以下工具箱:
建议Matlab版本:R2020b及以上,因为用到了新的图计算函数。
matlab复制function [selected_features, scores] = ilfs_feature_selection(X, y, k)
% X: n×d矩阵,n样本数,d特征数
% y: n×1标签向量
% k: 近邻参数
[n,d] = size(X);
% 预处理:标准化特征
X = zscore(X);
% 计算自适应带宽
sigma = zeros(d,1);
for i = 1:d
dists = pdist2(X(:,i), X(:,i));
[~, idx] = sort(dists, 2);
sigma(i) = median(dists(sub2ind([n,n], 1:n, idx(:,k+1)')));
end
% 构建相似矩阵(考虑类别信息)
S = zeros(d);
for i = 1:d
for j = i:d
diff = X(:,i) - X(:,j);
class_weights = (y == y'); % 同类样本权重更高
S(i,j) = sum(exp(-diff.^2/(sigma(i)*sigma(j))) .* diag(class_weights));
S(j,i) = S(i,j);
end
end
% 计算拉普拉斯矩阵
D = diag(sum(S,2));
L = D - S;
% 计算特征得分
scores = zeros(d,1);
for i = 1:d
fi = X(:,i);
scores(i) = (fi'*L*fi) / (fi'*D*fi + eps);
end
% 返回排序后的特征索引
[~, selected_features] = sort(scores, 'ascend');
end
近邻参数k:
并行计算优化:
在构建相似矩阵时,可以将外层循环改为parfor:
matlab复制parfor i = 1:d
% ... 计算S(i,:) ...
end
内存优化:
当特征数>10000时,建议分块计算相似矩阵:
matlab复制block_size = 1000;
for block_start = 1:block_size:d
block_end = min(block_start+block_size-1, d);
% 计算当前块的相似度...
end
使用威斯康星乳腺癌诊断数据集(WDBC):
matlab复制load('wdbc.dat'); % 569样本×30特征
X = wdbc(:,3:end); % 特征
y = wdbc(:,2); % 诊断结果(B/M)
matlab复制% 步骤1:初步筛选(ANOVA)
[pvals,~] = anova1(X, y, 'off');
retain_idx = pvals < 0.05;
X_filtered = X(:, retain_idx);
% 步骤2:ILFS选择
[selected, scores] = ilfs_feature_selection(X_filtered, y, 10);
% 步骤3:可视化
figure;
bar(scores(selected(1:15)));
xlabel('特征排名');
ylabel('ILFS得分');
title('Top 15重要特征');
| 特征选择方法 | 准确率 | AUC | 特征数 |
|---|---|---|---|
| 全特征 | 92.3% | 0.941 | 30 |
| 方差阈值 | 93.1% | 0.952 | 22 |
| ILFS | 95.6% | 0.971 | 15 |
注意:实际运行时建议使用10折交叉验证,上表是5次实验的平均结果。ILFS选择的特征虽然最少,但包含了更多与肿瘤形态相关的关键特征。
matlab复制% 去重处理
[~, unique_idx] = unique(X', 'rows');
X = X(:, unique_idx);
% 增大k值
optimal_k = round(sqrt(size(X,1)));
对于包含连续型和离散型特征的数据集:
matlab复制% 对于连续特征
sim_cont = exp(-norm(f1_cont-f2_cont)^2/sigma^2);
% 对于离散特征
sim_cat = sum(f1_cat == f2_cat)/length(f1_cat);
% 综合相似度
S(i,j) = alpha*sim_cont + (1-alpha)*sim_cat;
其中alpha是连续特征的权重系数,通常取0.7-0.9在深度神经网络的嵌入层后应用ILFS:
matlab复制% 获取深度特征
deep_features = activations(net, imds, 'fc_1');
% 特征选择
[selected, ~] = ilfs_feature_selection(deep_features, labels, 8);
% 重新训练分类器
new_features = deep_features(:, selected(1:50));
对于多标签分类问题,修改相似度计算:
matlab复制% 原代码中的:
class_weights = (y == y');
% 改为:
class_weights = 1 - pdist2(y, y, 'hamming');
将ILFS得分与t-SNE结合:
matlab复制[selected, scores] = ilfs_feature_selection(X, y, 10);
X_tsne = tsne(X(:, selected(1:10)));
figure;
gscatter(X_tsne(:,1), X_tsne(:,2), y);
title('ILFS选择特征后的t-SNE可视化');
在实际项目中,我发现ILFS算法特别适合处理以下场景:
最后分享一个实用技巧:当处理超大规模数据时,可以先对数据进行谱聚类,然后在每个簇内分别应用ILFS,最后合并结果。这种方法我在处理10万+特征的基因组数据时,能将运行时间从8小时缩短到40分钟左右。