Matlab利用隨機森林(RF)算法實現(xiàn)回歸預(yù)測詳解
本文分為兩部分,首先是對代碼進行分段、詳細講解,方便大家理解;隨后是完整代碼,方便大家自行嘗試。另外,關(guān)于基于MATLAB的神經(jīng)網(wǎng)絡(luò)(ANN)代碼與詳細解釋,我們將在后期博客中介紹。
1 分解代碼
1.1 最優(yōu)葉子節(jié)點數(shù)與樹數(shù)確定
首先,我們需要對RF對應(yīng)的葉子節(jié)點數(shù)與樹的數(shù)量加以擇優(yōu)選取。
%% 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
是為了多次循環(huán),防止最優(yōu)結(jié)果受到隨機干擾;大家如果不需要,可以將這句話刪除。
RFLeaf
定義初始的葉子節(jié)點個數(shù),我這里設(shè)置了從5
到500
,也就是從5
到500
這個范圍內(nèi)找到最優(yōu)葉子節(jié)點個數(shù)。
Input
與Output
分別是我的輸入(自變量)與輸出(因變量),大家自己設(shè)置即可。
運行后得到下圖。
首先,我們看到MSE
最低的線是紅色的,也就是5
左右的葉子節(jié)點數(shù)比較合適;再看各個線段大概到100
左右就不再下降,那么樹的個數(shù)就是100
比較合適。
1.2 循環(huán)準備
由于機器學(xué)習(xí)往往需要多次執(zhí)行,我們就在此先定義循環(huán)。
%% Cycle Preparation RFScheduleBar=waitbar(0,'Random Forest is Solving...'); RFRMSEMatrix=[]; RFrAllMatrix=[]; RFRunNumSet=10; for RFCycleRun=1:RFRunNumSet
其中,RFRMSEMatrix
與RFrAllMatrix
分別用來存放每一次運行的RMSE、r結(jié)果,RFRunNumSet
是循環(huán)次數(shù),也就是RF運行的次數(shù)。
1.3 數(shù)據(jù)劃分
接下來,我們需要將數(shù)據(jù)劃分為訓(xùn)練集與測試集。這里要注意:RF其實一般并不需要劃分訓(xùn)練集與測試集,因為其可以采用袋外誤差(Out of Bag Error,OOB Error)來衡量自身的性能。但是因為我是做了多種機器學(xué)習(xí)方法的對比,需要固定訓(xùn)練集與測試集,因此就還進行了數(shù)據(jù)劃分的步驟。
%% 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
是訓(xùn)練集的因變量,TrainVARI
是訓(xùn)練集的自變量;TestYield
是測試集的因變量,TestVARI
是測試集的自變量。
因為我這里是做估產(chǎn)回歸的,因此變量名稱就帶上了Yield
,大家理解即可。
1.4 隨機森林實現(xiàn)
這部分代碼其實比較簡單。
%% 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部分中我們確定的最優(yōu)樹個數(shù)與最優(yōu)葉子節(jié)點個數(shù),RFModel
就是我們所訓(xùn)練的模型,RFPredictYield
是預(yù)測結(jié)果,RFPredictConfidenceInterval
是預(yù)測結(jié)果的置信區(qū)間。
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);
在這里,我定義了當(dāng)RMSE滿足<400
這個條件時,模型將自動停止;否則將一直執(zhí)行到本文1.2部分中我們指定的次數(shù)。其中,模型每一次運行都會將RMSE與r結(jié)果記錄到對應(yīng)的矩陣中。
1.6 變量重要程度排序
接下來,我們結(jié)合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');
這里代碼就不再具體解釋了,大家會得到一幅圖,是每一個自變量對因變量的重要程度,數(shù)值越大,重要性越大。
其中,我注釋掉的這段是依據(jù)我當(dāng)時的數(shù)據(jù)情況來的,大家就不用了。
更新:
這里請大家注意,上述代碼中我注釋掉的內(nèi)容,是依據(jù)每一幅圖像的名稱對重要性排序的X
軸(也就是VariableImportanceX
)加以注釋(我當(dāng)時做的是依據(jù)遙感圖像估產(chǎn),因此每一個輸入變量的名稱其實就是對應(yīng)的圖像的名稱),所以使得得到的變量重要性柱狀圖的X
軸會顯示每一個變量的名稱。大家用自己的數(shù)據(jù)來跑的時候,可以自己設(shè)置一個變量名稱的字段元胞然后放到VariableImportanceX
,然后開始figure
繪圖;如果在輸入數(shù)據(jù)的特征個數(shù)(也就是列數(shù))比較少的時候,也可以用我上述代碼中間的這個for i=1:size(Input,2)
循環(huán)——這是一個偷懶的辦法,也就是將重要性排序圖的X軸中每一個變量的名稱顯示為一個正方形,如下圖紅色圈內(nèi)。這里比較復(fù)雜,因此如果大家這一部分沒有搞明白或者是一直報錯,在本文下方直接留言就好~
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
后的內(nèi)容是需要保存的變量名稱。
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');
至此,大功告成。
到此這篇關(guān)于Matlab利用隨機森林(RF)算法實現(xiàn)回歸預(yù)測詳解的文章就介紹到這了,更多相關(guān)Matlab回歸預(yù)測內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++使用循環(huán)計算標(biāo)準差的代碼實現(xiàn)
在C++中,計算標(biāo)準差可以使用循環(huán)來實現(xiàn),本文給大家介紹了一個示例代碼,演示了如何使用循環(huán)計算標(biāo)準差,文中示例代碼介紹的非常詳細,具有一定的參考價值,需要的朋友可以參考下2023-12-12C++ Qt開發(fā)之使用QHostInfo查詢主機地址
Qt 是一個跨平臺C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺窗體應(yīng)用程序,本文將重點介紹如何運用QHostInfo組件實現(xiàn)對主機地址查詢功能,希望對大家有所幫助2024-03-03c語言程序設(shè)計文件操作方法示例(CreateFile和fopen)
c主要的文件操作函數(shù)有:CreateFile,CloseHandle,ReadFile,WriteFile,SetFilePointer,GetFileSize。其中的讀寫操作是以字符為單位,獲得文件大小也是以字符為單位。2013-12-12C++編寫的WebSocket服務(wù)端客戶端實現(xiàn)示例代碼
本文主要介紹了C++編寫的WebSocket服務(wù)端客戶端實現(xiàn)示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10