一 . L0 范数正则化特征选择
- 穷举计算法
在面对变量选择时, 我们要进行后验表示,我们另 rj = 1, 表示第j 个特征与此后验是相关的, 其中后验表达为
假如有样本 N = 20 ,维数 D = 10,进行线性回归模型, 其中数据和噪声为正太分布的,, 我们一般会要 求K 稀疏,表示稀疏的程度。 如K = 5,表示 有5个w 为非0, 即我们用 w = (0, -1.67, 0.13, 0, 0, 1.19, 0, -0.04, 0.33, 0) , 并且噪声方差满足
。
其实我们可以枚举 2^10 = 1024 种模型来计算p(r|D), 通过组合所有的特征来枚举,最终得到最大的八组模型为:
进行大量的模型枚举判断真的不太容易, 我们因而考虑一个自然而然的后验模型 MAP 估计, 似然加上先验,
在实际计算时,通常不会计算所有情况的概率密度,而是利用中值模型:
这就需要计算后验经验概率(marginal inclusion probabilities) 。
我们可以分别得到每个特征对应的后验概率情况:
如果上述 MAP 估计或是 marginal inclusion probabilities 都无效的话,就要考虑算法加速。
首先先对上述计算进行模型实例化:
- The spike and slab model
- 加速优化方法
- 首先引入 MP 没有正交的情况
举个栗子:
如果 空间D = {x1, x2}, 且有 图表示 f 与 x1, x2 的关系为:
MP算法迭代会发现总是在 x1 和 x2 上反复迭代,即,这个就是信号(残值)在已选择的原子进行垂直投影的非正交性导致的。
这样就引进了 OMP 正交投影寻踪法。
- OMP 娓娓道来了:
有了上面 MP 的了解之后, 这里就容易多了:
每次迭代都保证 残差与 现有的空间正交: , 这里OMP 准确的是两个迭代,保证向后的计算是在正交情况下进行的。
首先我们假设已经有了 第 k 阶 的结果 :
我们要做的是 进行更新,k->k+1, 注意的是 这里的 , 第 k 次的残差与 已添加所有的特征向量都正交。
k+1 :
这里的 k+1 次迭代情况, 与上述第 k 次 满足同样的条件。
两者做差有:
因为在D 中的各个特征向量 不是正交的, 因此我们构造了一个辅助方程 来表示 , 与前 xn 的关系,
在Span(x1, x2..... ,xn)上的正交投影操作, 后面的一项是残差。 。 (对的不要理解错误了,是残差与已经添加的特征向量正交,而向量之间不正交。)
如果此式的系数项和常数项分别满足 ,则此公式一定满足 。
这样就完成了得带的参数求解的过程, 其中 , 可通过 计算得出,后续参考中的《OMP_Krishnaprasad.pdf》给出了 其计算过程,rk 可以通过求出的
,来求残差。 这样可以得到第k+1 步迭代的参数。
, 这样只要经过 N步(方向向量的个数),就可全部迭代完毕。
算法的过程:
以上的算法的理解是建立在参数的理解过程的。 另外更简单的方法是 直接选特征(最大内积),然后用最小二乘直接计算参数,从而方面很多。
二、L0正则化实例
Prostate数据集上回归分析
- 数据集介绍
该数据集包括了97位准备做前列腺根治手术病人的前列腺特殊抗原(lpsa: log prostate specific antigen)和8个临床指标:
lcavol:log cancel volume (肿瘤体积)
lweight:log prostate weight (前列腺重量)
age:(年龄)
lbph:log bengin prostatic hypcrplasia (良性前列腺增生量)
svi:seminal vesicle invasion (精囊浸润)
lcp:log of capsular penetration (包膜穿透)
gleason:gleason score (Gleason积分)
pgg45:percent of Gleason scores 4 or 5 ( Gleason4/5所占百分比 )。
2. 现在要做用L0正则做线性回归:
用L0 就是对自己进行选择的过程,
方法一: 穷举搜索:
所有可能的模型共有 个。对每个模型计算其最小二乘结果,并比较每个模型的训练误差和测试误差。
首先读取数据集:
istrain: [1x97 logical]
y: [97x1 double]
names: {1x9 cell}
X: [97x8 double]
ytest: [30x1 double]
Xtrain: [67x8 double]
ytrain: [67x1 double]
Xtest: [30x8 double]
读取数据,然后送去穷举:
k = load('prostate.mat') % from prostateDataMake
[n d] = size(Xtrain);
[w, mseTrain, mseTest, sz, members] = allSubsetsRegression(Xtrain, ytrain, Xtest, ytest, 0:d, 1);
穷举的过程,首先是标准化数据:
if doStandardize %对训练集x进行标准化
[Xtrain, mu] = center(Xtrain);
[Xtrain, s] = mkUnitVariance(Xtrain);
if ~isempty(Xtest)
Xtest = center(Xtest, mu);
Xtest = mkUnitVariance(Xtest, s);
end
end
之后标准化结束后,要得到所有的组合 256种,
ndx = ind2subv( 2*ones(1,d),1:(2^d) ) -1; %256×8 是个矩阵,子矩阵的排列组合。
NN = size(ndx,1);
之后开始进行枚举, 并记录下每一次的计算的结果:
j = 1;
for i=1:size(ndx,1)
include = find(ndx(i,:));
if ~ismember(length(include), allowableSizes)
%fprintf('skipping size %d\n', length(include))
continue
else
%fprintf('including %s\n', sprintf('%d,', include));
end
members{j} = include;
sz(j) = length(include);
w{j} = [ones(n,1) Xtrain(:,include)]\ytrain;
ypredTrain = [ones(n,1) Xtrain(:,include)]*w{j};
RSS = sum((ytrain-ypredTrain).^2);
mseTrain(j) = RSS/n;
if ~isempty(Xtest)
ntest = size(Xtest, 1);
ypredTest = [ones(ntest,1) Xtest(:,include)]*w{j};
mseTest(j) = mean((ypredTest-ytest).^2);
else
mseTest = [];
end
j = j + 1;
end
分别找到不同个数特征下最好的情况,然后找到测试结果最好的情况。
for i=0:d
ndx = find(sz==i);
[besTrainScore(i+1) bestTrainSet] = min(mseTrain(ndx));
[besTestScore(i+1) bestTestSet] = min(mseTest(ndx));
end
[bestTestMSE ndx_star] = min(mseTest);
w_star = w(ndx_star);
model_star = members(ndx_star);
bestTrainMSE = mseTrain(ndx_star);
bestTrainMSE
bestTestMSE
figure(1);clf
plot(0:d,besTrainScore, 'bo-')
hold on
plot(0:d,besTestScore, 'ro-')
%the selected/best model
[bestTestMSE kstar] = min(besTestScore);
vline(kstar-1,'r-.'); %将顶点连线画出来
xlabel('subset size')
legend('best RSS on training set', 'best RSS on testing set');
title('all subsets on prostate cancer')
效果图:
这里的测试误差是模型在30个测试样本上的真正测试误差,不是用交叉验证估计的结果。训练误差随着模型复杂度的增加,一直下降;但测试误差开始随模型复杂度增加而下降,当模型达到一定复杂度(特征数目为3)时,测试误差随着模型复杂度的增加而增加。所以当模型复杂度高时,模型的训练误差很小,但测试误差较大,这就发生了过拟合现象。如果以真实测试误差为标准,则我们选择的最佳模型为子集大小为k=3。
最佳结果模型的参数表为:
该模型的训练误差为0.6309,在测试集上的真实测试误差为0.3828。
方法二: BIC 准则
如果不是用真正的测试误差,而是用BIC准则作为测试误差的估计的话,得到的最佳模型为子集大小为k=3。 其中BIC 判别分数为:
这里若噪声的方差未知,可用其极大似然估计代替, dof(M) 为模型M 中的自由参数的数目, 在线性回归中为特征数目。
首先读取数据:
load('prostate.mat') % from prostateDataMake
[n d] = size(Xtrain);
[w, mseTrain, mseTest, mseTest_BIC, sz, members] = allSubsetsRegression_BIC(Xtrain, ytrain, Xtest, ytest, 0:d, 1);
标准化:
if doStandardize
[Xtrain, mu] = center(Xtrain);
[Xtrain, s] = mkUnitVariance(Xtrain);
if ~isempty(Xtest)
Xtest = center(Xtest, mu);
Xtest = mkUnitVariance(Xtest, s);
end
end
然后似然估计 噪声方差
%OLS = MLE, estimate the variance of the noise, which will be used in compute
%BIC
beta_LS = [ones(n,1) Xtrain]\ytrain;
ypredTrain = [ones(n,1) Xtrain]*beta_LS; % Predicted responses at each data point.
RSS = sum((ytrain-ypredTrain).^2); % Residuals.
sig2_hat = RSS/(n-d-1);
特征组合 并穷举记录结果:
ndx = ind2subv( 2*ones(1,d),1:(2^d) ) -1;
NN = size(ndx,1);
j = 1;
for i=1:size(ndx,1)
include = find(ndx(i,:));
if ~ismember(length(include), allowableSizes)
%fprintf('skipping size %d\n', length(include))
continue
else
%fprintf('including %s\n', sprintf('%d,', include));
end
members{j} = include;
sz(j) = length(include);
w{j} = [ones(n,1) Xtrain(:,include)]\ytrain;
ypredTrain = [ones(n,1) Xtrain(:,include)]*w{j};
RSS = sum((ytrain-ypredTrain).^2);
mseTrain(j) = RSS/n;
%BIC estimation of mseTest
mseTest_BIC(j) = mseTrain(j) + log(n)*sz(j)*sig2_hat/n; % BIC;
%test
if ~isempty(Xtest)
ntest = size(Xtest, 1);
ypredTest = [ones(ntest,1) Xtest(:,include)]*w{j};
mseTest(j) = mean((ypredTest-ytest).^2);
else
mseTest = [];
end
j = j + 1;
end
选出最小误差结果,并画出来:
for i=0:d
ndx = find(sz==i);
[besTrainScore(i+1) bestTrainSet] = min(mseTrain(ndx));
[besTestScore(i+1) bestTestSet] = min(mseTest(ndx));
[besTestScore_BIC(i+1) bestTestSet_BIC] = min(mseTest_BIC(ndx)); %最小的BIC 的结果
end
[bestBIC ndx_star] = min(mseTest_BIC);
w_star = w(ndx_star);
model_star = members(ndx_star);
bestmseTrain = mseTrain(ndx_star);
bestmseTest = mseTest(ndx_star);
bestBIC
bestmseTrain
bestmseTest
figure
clf
plot(0:d,besTestScore_BIC, 'mo-')
hold on
plot(0:d,besTrainScore, 'bo-')
hold on
plot(0:d,besTestScore, 'ro-')
%the selected/best model
[bestBIC kstar] = min(besTestScore_BIC);
hold on
vline(kstar-1,'m-.');
xlabel('subset size')
ylabel('error')
legend('best BIC score','best RSS on training set', 'best RSS on testing set');
title('all subsets on prostate cancer BIC')
结果图:
其中参数结果为:
该模型的训练误差为0.5210,在测试集上的真实测试误差为0.4815。
方法三: 交叉验证如果用10折交叉验证测试误差估计,并采用1倍标准差原则的话,得到的最佳模型为子集大小为k=2。
首先读取数据:
load('prostate.mat') % from prostateDataMake
[n d] = size(Xtrain);
[w, mseTrain, mseTest,model] = allSubsetsRegression_CV(Xtrain, ytrain, Xtest, ytest, 0:d, 1);
标准化数据:
%标准化数据
if doStandardize
[Xtrain, mu] = center(Xtrain);
[Xtrain, s] = mkUnitVariance(Xtrain);
if ~isempty(Xtest)
Xtest = center(Xtest, mu);
Xtest = mkUnitVariance(Xtest, s);
end
end
将数据分成10折, 比如100 个数据,第一次[0-10] test, [11-100] train, 第二次[11-20] test, [0-10],[21-100] train .... 等等
%cross validation
Nfolds = 10;
seed= 0; rand('state', seed);
sizes = 0:d;
perm = randperm(n);
xtrainAll = Xtrain(perm,:);
ytrainAll = ytrain(perm);
[trainfolds, testfolds] = Kfold(size(xtrainAll,1), Nfolds); %10 folds 交叉验证
clear mseCVTrain mseCVTest
for f=1:length(trainfolds)
xtrainCV = xtrainAll(trainfolds{f},:);
ytrainCV = ytrainAll(trainfolds{f});
xtestCV = xtrainAll(testfolds{f},:);
ytestCV = ytrainAll(testfolds{f});
[w, mseCVTrainAll(f,:), mseCVTestAll(f,:), sz, members, df, mseCVTest(f,:)] = ...
allSubsetsRegression(xtrainCV, ytrainCV, xtestCV, ytestCV, sizes, 0);
end
算出每个折的一倍标准差,以及每折得到的对应的个数求出的均方差的平均。
%mseCVTest 这个得到的是那个最好的测试的结果,就是每折之后, 选出的[], 1,2 ,3 ...,8 枚举过的最小的均方误差。
mseCVMean = mean(mseCVTest,1); %每一折的均方差的平均 , 即列的平均啊, 最小的那个测试标准偏差。
mseCVse = std(mseCVTest,[],1)/sqrt(Nfolds); %一倍标准差, 标准偏差, 1×9
然后是其一倍标准差表示, 以及找到在变量最少(模型最简单)的情况下, 满足最小均方差一倍标准差范围的。
figure; %误差带的上下各为 mseCVse
errorbar(df, mseCVMean, mseCVse); % confidence intervals of data or the deviation along a curve.
kstar = oneStdErrorRule(mseCVMean, mseCVse); %找出根据均值和一倍标准差, 最好的一个满足的。, 因为最小到大其特征数在增加,因而其复杂度在增加。
hold on
vline(kstar,'r-.');
xlabel('size of subset')
ylabel('cv error')
title(sprintf('all subsets CV'))
通过得到这个最少变量得个数,在这个最小变量个数下能表示 此模型的情况。
% Refit using all training data to find set of chosen size
[w, mseTrain, junk, junk2, members] = ...
allSubsetsRegression(Xtrain, ytrain, [], [], sizes(kstar), 0); %所以找到两个的最佳的那个w,
[junk,best]=min(mseTrain);
w = w(best);
model = members{best};
mseTrain = mseTrain(best);
model
if ~isempty(Xtest)
ntest = size(Xtest, 1);
ypredTest = [ones(ntest,1) Xtest(:,model)]* cell2mat(w);
mseTest = mean((ypredTest-ytest).^2);
else
mseTest = 0;
end
mseTrain
mseTest
该模型的训练误差为0. 5536,在测试集上的真实测试误差为0.5737。
我们以BIC准则估计模型的测试误差,采用正交投影寻踪每次增加一个与当前残差最相关的特征,然后更新模型参数。前向逐步回归选择的模型为子集大小为4;当 特征数目变成5时,BIC分数增加,迭代终止。
读取数据:
load('prostate.mat') % from prostateDataMake
[n d] = size(Xtrain);
[w, mseTrain, mseTest, mseTest_BIC, sz, members] = OMP_BIC(Xtrain, ytrain, Xtest, ytest, 0:d, 1);
数据标准化:
if doNormalized
[Xtrain, mu] = center(Xtrain);
[Xtrain, norm2] = normalize(Xtrain);
if ~isempty(Xtest)
Xtest = center(Xtest, mu);
Xtest = normalize(Xtest, norm2);
end
end
然后最大似然求方差
%OLS, for estimate the variance of the noise, which will be used in compute
%BIC
beta_LS = [ones(n,1) Xtrain]\ytrain;
ypredTrain = [ones(n,1) Xtrain]*beta_LS; % Predicted responses at each data point.
RSS = sum((ytrain-ypredTrain).^2); % Residuals.
sig2_hat = RSS/n;
当数据为空时, 最开始的初始化情况有:
% the empty model
include = []; %包含的特征
j = 1;
members{j} = include;
sz(j) = length(include);
w0 = mean(ytrain);
w{j} = w0;
ypredTrain = [ones(n,1) Xtrain(:,include)]* w{j} ;
RSS = sum((ytrain-ypredTrain).^2);
mseTrain(j) = RSS/n;
%BIC estimation of mseTest
mseTest_BIC(j) = mseTrain(j) + log(n)*sz(j)*sig2_hat/n; % BIC;
bestBIC = mseTest_BIC(j);
%test
if ~isempty(Xtest)
ntest = size(Xtest, 1);
ypredTest = [ones(ntest,1) Xtest(:,include)]*w{j};
mseTest(j) = mean((ypredTest-ytest).^2);
else
mseTest = [];
end
ndx_star = j;
然后进入OMP 逐渐的迭代过程,利用BIC 分数作为判别的标准,当BIC 分数增加时(误差变大)迭代终止:
j = j+1;
for i = 1 : d
%当前模型的残差
residual = ytrain-ypredTrain;
%残差与特征之间的相关性(投影)
proj = Xtrain' * residual;
%选择与残差最相关的特征
[maxval, bestk] = max(abs(proj));
include = [include bestk]; %add the mink feature
members{j} = include; % add best k th feature temp
sz(j) = length(members{j});
%least squares
w{j} = [ones(n,1) Xtrain(:,members{j})]\ytrain;
ypredTrain = [ones(n,1) Xtrain(:,members{j})]* w{j} ;
RSS = sum((ytrain-ypredTrain).^2);
mseTrain(j) = RSS/n;
%BIC estimation of mseTest
mseTest_BIC(j) = mseTrain(j) + log(n)*sz(j)*sig2_hat/n; % BIC; 利用此分数来进行终止条件判断。
%test
if ~isempty(Xtest)
ntest = size(Xtest, 1);
ypredTest = [ones(ntest,1) Xtest(:,members{j})]* w{j} ;
mseTest(j) = mean((ypredTest-ytest).^2);
else
mseTest = [];
end
if mseTest_BIC(j) > bestBIC % the BIC tend to increase
break;
else
bestBIC = mseTest_BIC(j);
end
j = j + 1;
end
结果:
三、总结
通过L0 正则化进行特征选择, 但是一般情况L0 正则导致函数不光滑, 优化方法不容易计算, 因此,我们将继续研究L1正则化, 作为L0 的 “最优突近似”。
四、参考文献
1. << Machine Learning A Probabilistic Perspective >>
2. Orthogonal Matching Pursuit:Recursive Function Approximat ion with Applications to Wavelet Decomposition
3. 机器学习中的范数规则化之(一)L0、L1与L2范数 - http://blog.csdn.net/zouxy09/article/details/24971995
本文介绍了L0正则化在特征选择中的应用,包括穷举计算法和MAP估计,讨论了正交投影寻踪法(OMP)作为优化手段。通过Prostate数据集的案例分析,展示了L0正则化在实际问题中的运用,并对比了不同选择模型的方法,如BIC准则和交叉验证。最后,指出L0正则化的挑战及其与L1正则化的联系。

4万+

被折叠的 条评论
为什么被折叠?



