本文已参与「新人创造礼」活动,一同开启创造之路。
本文介绍根据MATLAB,使用随机森林(RF)算法完成回归猜测,以及自变量重要性排序的操作。
本文分为两部分,首要是对代码进行分段、详细讲解,方便咱们了解;随后是完好代码,方便咱们自行测验。别的,关于根据MATLAB的神经网络(ANN)代码与详细解说,咱们能够查看我的其他文章
1 分化代码
1.1 最优叶子节点数与树数确定
首要,咱们需求对RF对应的叶子节点数与树的数量加以择优选取。
%% Number of Leaves and Trees Optimization
for RFOptimizationNum=1:5
RFLeaf=[5,10,20,50,100,200,500];
col='rgbcmyk';
figure('Name','RF Leaves and Trees');
for i=1:length(RFLeaf)
RFModel=TreeBagger(2000,Input,Output,'Method','R','OOBPrediction','On','MinLeafSize',RFLeaf(i));
plot(oobError(RFModel),col(i));
hold on
end
xlabel('Number of Grown Trees');
ylabel('Mean Squared Error') ;
LeafTreelgd=legend({'5' '10' '20' '50' '100' '200' '500'},'Location','NorthEast');
title(LeafTreelgd,'Number of Leaves');
hold off;
disp(RFOptimizationNum);
end
其间,RFOptimizationNum
是为了屡次循环,避免最优成果受到随机搅扰;咱们如果不需求,能够将这句话删去。RFLeaf
界说初始的叶子节点个数,我这儿设置了从5
到500
,也便是从5
到500
这个范围内找到最优叶子节点个数。Input
与Output
别离是我的输入(自变量)与输出(因变量),咱们自己设置即可。
运行后得到下图。
首要,咱们看到MSE
最低的线是红色的,也便是5
左右的叶子节点数比较适宜;再看各个线段大概到100
左右就不再下降,那么树的个数便是100
比较适宜。
1.2 循环准备
由于机器学习往往需求屡次履行,咱们就在此先界说循环。
%% Cycle Preparation
RFScheduleBar=waitbar(0,'Random Forest is Solving...');
RFRMSEMatrix=[];
RFrAllMatrix=[];
RFRunNumSet=10;
for RFCycleRun=1:RFRunNumSet
其间,RFRMSEMatrix
与RFrAllMatrix
别离用来寄存每一次运行的RMSE、r成果,RFRunNumSet
是循环次数,也便是RF运行的次数。
1.3 数据区分
接下来,咱们需求将数据区分为练习集与测验集。这儿要留意:RF其实一般并不需求区分练习集与测验集,由于其能够选用袋外差错(Out of Bag Error,OOB Error)来衡量本身的性能。可是由于我是做了多种机器学习方法的比照,需求固定练习集与测验集,因而就还进行了数据区分的过程。
%% Training Set and Test Set Division
RandomNumber=(randperm(length(Output),floor(length(Output)*0.2)))';
TrainYield=Output;
TestYield=zeros(length(RandomNumber),1);
TrainVARI=Input;
TestVARI=zeros(length(RandomNumber),size(TrainVARI,2));
for i=1:length(RandomNumber)
m=RandomNumber(i,1);
TestYield(i,1)=TrainYield(m,1);
TestVARI(i,:)=TrainVARI(m,:);
TrainYield(m,1)=0;
TrainVARI(m,:)=0;
end
TrainYield(all(TrainYield==0,2),:)=[];
TrainVARI(all(TrainVARI==0,2),:)=[];
其间,TrainYield
是练习集的因变量,TrainVARI
是练习集的自变量;TestYield
是测验集的因变量,TestVARI
是测验集的自变量。
由于我这儿是做估产回归的,因而变量称号就带上了Yield
,咱们了解即可。
1.4 随机森林完成
这部分代码其实比较简单。
%% RF
nTree=100;
nLeaf=5;
RFModel=TreeBagger(nTree,TrainVARI,TrainYield,...
'Method','regression','OOBPredictorImportance','on', 'MinLeafSize',nLeaf);
[RFPredictYield,RFPredictConfidenceInterval]=predict(RFModel,TestVARI);
其间,nTree
、nLeaf
便是本文1.1部分中咱们确定的最优树个数与最优叶子节点个数,RFModel
便是咱们所练习的模型,RFPredictYield
是猜测成果,RFPredictConfidenceInterval
是猜测成果的置信区间。
1.5 精度衡量
在这儿,咱们用RMSE与r衡量模型精度。
%% Accuracy of RF
RFRMSE=sqrt(sum(sum((RFPredictYield-TestYield).^2))/size(TestYield,1));
RFrMatrix=corrcoef(RFPredictYield,TestYield);
RFr=RFrMatrix(1,2);
RFRMSEMatrix=[RFRMSEMatrix,RFRMSE];
RFrAllMatrix=[RFrAllMatrix,RFr];
if RFRMSE<400
disp(RFRMSE);
break;
end
disp(RFCycleRun);
str=['Random Forest is Solving...',num2str(100*RFCycleRun/RFRunNumSet),'%'];
waitbar(RFCycleRun/RFRunNumSet,RFScheduleBar,str);
end
close(RFScheduleBar);
在这儿,我界说了当RMSE满足<400
这个条件时,模型将主动停止;否则将一向履行到本文1.2部分中咱们指定的次数。其间,模型每一次运行都会将RMSE与r成果记录到对应的矩阵中。
1.6 变量重要程度排序
接下来,咱们结合RF算法的一个功能,对一切的输入变量进行分析,去获取每一个自变量对因变量的解说程度。
%% Variable Importance Contrast
VariableImportanceX={};
XNum=1;
% for TifFileNum=1:length(TifFileNames)
% if ~(strcmp(TifFileNames(TifFileNum).name(4:end-4),'MaizeArea') | ...
% strcmp(TifFileNames(TifFileNum).name(4:end-4),'MaizeYield'))
% eval(['VariableImportanceX{1,XNum}=''',TifFileNames(TifFileNum).name(4:end-4),''';']);
% XNum=XNum+1;
% end
% end
for i=1:size(Input,2)
eval(['VariableImportanceX{1,XNum}=''',i,''';']);
XNum=XNum+1;
end
figure('Name','Variable Importance Contrast');
VariableImportanceX=categorical(VariableImportanceX);
bar(VariableImportanceX,RFModel.OOBPermutedPredictorDeltaError)
xtickangle(45);
set(gca, 'XDir','normal')
xlabel('Factor');
ylabel('Importance');
这儿代码就不再详细解说了,咱们会得到一幅图,是每一个自变量对因变量的重要程度,数值越大,重要性越大。
其间,我注释掉的这段是根据我当时的数据情况来的,咱们就不用了。
更新:这儿请咱们留意,上述代码中我注释掉的内容,是根据每一幅图画的称号对重要性排序的X
轴(也便是VariableImportanceX
)加以注释(我当时做的是根据遥感图画估产,因而每一个输入变量的称号其实便是对应的图画的称号),所以使得得到的变量重要性柱状图的X
轴会显现每一个变量的称号。咱们用自己的数据来跑的时分,能够自己设置一个变量称号的字段元胞然后放到VariableImportanceX
,然后开始figure
绘图;如果在输入数据的特征个数(也便是列数)比较少的时分,也能够用我上述代码中心的这个for i=1:size(Input,2)
循环——这是一个偷闲的办法,也便是将重要性排序图的X轴中每一个变量的称号显现为一个正方形,如下图红色圈内。这儿比较复杂,因而如果咱们这一部分没有搞明白或者是一向报错,在本文下方直接留言就好~
1.7 保存模型
接下来,就能够将适宜的模型保存。
%% RF Model Storage
RFModelSavePath='G:\CropYield\02_CodeAndMap\00_SavedModel\';
save(sprintf('%sRF0410.mat',RFModelSavePath),'nLeaf','nTree',...
'RandomNumber','RFModel','RFPredictConfidenceInterval','RFPredictYield','RFr','RFRMSE',...
'TestVARI','TestYield','TrainVARI','TrainYield');
其间,RFModelSavePath
是保存路径,save
后的内容是需求保存的变量称号。
2 完好代码
完好代码如下:
%% Number of Leaves and Trees Optimization
for RFOptimizationNum=1:5
RFLeaf=[5,10,20,50,100,200,500];
col='rgbcmyk';
figure('Name','RF Leaves and Trees');
for i=1:length(RFLeaf)
RFModel=TreeBagger(2000,Input,Output,'Method','R','OOBPrediction','On','MinLeafSize',RFLeaf(i));
plot(oobError(RFModel),col(i));
hold on
end
xlabel('Number of Grown Trees');
ylabel('Mean Squared Error') ;
LeafTreelgd=legend({'5' '10' '20' '50' '100' '200' '500'},'Location','NorthEast');
title(LeafTreelgd,'Number of Leaves');
hold off;
disp(RFOptimizationNum);
end
%% Notification
% Set breakpoints here.
%% Cycle Preparation
RFScheduleBar=waitbar(0,'Random Forest is Solving...');
RFRMSEMatrix=[];
RFrAllMatrix=[];
RFRunNumSet=50000;
for RFCycleRun=1:RFRunNumSet
%% Training Set and Test Set Division
RandomNumber=(randperm(length(Output),floor(length(Output)*0.2)))';
TrainYield=Output;
TestYield=zeros(length(RandomNumber),1);
TrainVARI=Input;
TestVARI=zeros(length(RandomNumber),size(TrainVARI,2));
for i=1:length(RandomNumber)
m=RandomNumber(i,1);
TestYield(i,1)=TrainYield(m,1);
TestVARI(i,:)=TrainVARI(m,:);
TrainYield(m,1)=0;
TrainVARI(m,:)=0;
end
TrainYield(all(TrainYield==0,2),:)=[];
TrainVARI(all(TrainVARI==0,2),:)=[];
%% RF
nTree=100;
nLeaf=5;
RFModel=TreeBagger(nTree,TrainVARI,TrainYield,...
'Method','regression','OOBPredictorImportance','on', 'MinLeafSize',nLeaf);
[RFPredictYield,RFPredictConfidenceInterval]=predict(RFModel,TestVARI);
% PredictBC107=cellfun(@str2num,PredictBC107(1:end));
%% Accuracy of RF
RFRMSE=sqrt(sum(sum((RFPredictYield-TestYield).^2))/size(TestYield,1));
RFrMatrix=corrcoef(RFPredictYield,TestYield);
RFr=RFrMatrix(1,2);
RFRMSEMatrix=[RFRMSEMatrix,RFRMSE];
RFrAllMatrix=[RFrAllMatrix,RFr];
if RFRMSE<1000
disp(RFRMSE);
break;
end
disp(RFCycleRun);
str=['Random Forest is Solving...',num2str(100*RFCycleRun/RFRunNumSet),'%'];
waitbar(RFCycleRun/RFRunNumSet,RFScheduleBar,str);
end
close(RFScheduleBar);
%% Variable Importance Contrast
VariableImportanceX={};
XNum=1;
% for TifFileNum=1:length(TifFileNames)
% if ~(strcmp(TifFileNames(TifFileNum).name(4:end-4),'MaizeArea') | ...
% strcmp(TifFileNames(TifFileNum).name(4:end-4),'MaizeYield'))
% eval(['VariableImportanceX{1,XNum}=''',TifFileNames(TifFileNum).name(4:end-4),''';']);
% XNum=XNum+1;
% end
% end
for i=1:size(Input,2)
eval(['VariableImportanceX{1,XNum}=''',i,''';']);
XNum=XNum+1;
end
figure('Name','Variable Importance Contrast');
VariableImportanceX=categorical(VariableImportanceX);
bar(VariableImportanceX,RFModel.OOBPermutedPredictorDeltaError)
xtickangle(45);
set(gca, 'XDir','normal')
xlabel('Factor');
ylabel('Importance');
%% RF Model Storage
RFModelSavePath='G:\CropYield\02_CodeAndMap\00_SavedModel\';
save(sprintf('%sRF0410.mat',RFModelSavePath),'nLeaf','nTree',...
'RandomNumber','RFModel','RFPredictConfidenceInterval','RFPredictYield','RFr','RFRMSE',...
'TestVARI','TestYield','TrainVARI','TrainYield');