服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - Matlab利用随机森林(RF)算法实现回归预测详解

Matlab利用随机森林(RF)算法实现回归预测详解

2023-03-09 15:54疯狂学习GIS C/C++

这篇文章主要为大家详细介绍了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分别是我的输入(自变量)与输出(因变量),大家自己设置即可。

运行后得到下图。

Matlab利用随机森林(RF)算法实现回归预测详解

首先,我们看到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分别用来存放每一次运行的RMSEr结果,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 精度衡量

在这里,我们用RMSEr衡量模型精度。

%% 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部分中我们指定的次数。其中,模型每一次运行都会将RMSEr结果记录到对应的矩阵中。

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轴中每一个变量的名称显示为一个正方形,如下图红色圈内。这里比较复杂,因此如果大家这一部分没有搞明白或者是一直报错,在本文下方直接留言就好~

Matlab利用随机森林(RF)算法实现回归预测详解

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');

至此,大功告成。

到此这篇关于Matlab利用随机森林(RF)算法实现回归预测详解的文章就介绍到这了,更多相关Matlab回归预测内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/fkxxgis/p/17095368.html

延伸 · 阅读

精彩推荐
  • C/C++C++详解如何实现动态数组

    C++详解如何实现动态数组

    这篇文章主要为大家详细介绍了C++实现动态数组的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    肩上风骋9412023-02-14
  • C/C++十个超赞的C语言开源项目(推荐)

    十个超赞的C语言开源项目(推荐)

    今天分享10个超赞的C语言开源项目,希望这些内容能对大家有所帮助!...

    开源前线6042022-09-19
  • C/C++C语言实现三子棋方法

    C语言实现三子棋方法

    这篇文章主要为大家详细介绍了C语言实现三子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    幽沫沫3612021-10-20
  • C/C++解决 VSCode 编写 C++11 代码报红问题分析

    解决 VSCode 编写 C++11 代码报红问题分析

    今天在写 C++ 代码的时候用上 C++11 的特性,然后发现 VSCode 虽然可以编译通过,但是会在相应位置报红,这是怎么回事呢?下面小编给大家带来了解决方法...

    VeggieOrz6892022-01-12
  • C/C++简易Dota改键外挂程序制作

    简易Dota改键外挂程序制作

    利用全局钩子制作一个个性化的dota游戏改键功能,大家可以参考使用...

    C语言教程网12172021-01-10
  • C/C++C++中的异或运算符^的使用方法

    C++中的异或运算符^的使用方法

    本篇文章对C++中的异或运算符^的使用方法进行的详细的分析介绍,需要的朋友参考下...

    C++教程网6172020-11-26
  • C/C++Mygui中文换行问题解决方案

    Mygui中文换行问题解决方案

    相信大家解决了中文输入后一定会遇到如何解决中文输入的问题,中文输入换行问题是很多gui框架都存在的一个问题,需要的朋友可以了解下...

    脚本之家3472020-11-13
  • C/C++C指针原理教程之AT&T汇编

    C指针原理教程之AT&T汇编

    AT&T 汇编是一种和intel汇编在语法上完全不同的汇编语言,为避免混淆intel语法,本文只介绍AT&T汇编,AT&T的第一个特点就是每个寄存器名前必须加‘%’,立即...

    myhaspl12102021-07-21