注:需要先确定matlab里有无安装C++编译器
另外还需要预先安装一个随机森林的工具包下面代码才可运行
1.简述
随机森林
随机森林算法基于Bootstrap方法重采样,产生多个训练集。不同的是,随机森林算法在构建决策树的时候,采用了随机选取分裂属性集的方法。
随机森林就是通过集成学习的Bagging思想将多棵树集成的一种算法:它的基本单元就是决策树。随机森林的名称中有两个关键词,一个是“随机”,一个就是“森林”。“森林”很好理解,一棵叫做树,那么成百上千棵就可以叫做森林了,其实这也是随机森林的主要思想--集成思想的体现。“随机”的含义我们会在下面讲到。
我们要将一个输入样本进行分类,就需要将它输入到每棵树中进行分类。将若干个弱分类器的分类结果进行投票选择,从而组成一个强分类器,这就是随机森林bagging的思想.
按照如下规则生成:
(1)如果训练集大小为N,对于每棵树而言,随机且有放回地从训练集中的抽取N个训练样本(就是bootstrap sample方法, 拔靴法采样)作为该树的训练集;从这里我们可以知道:每棵树的训练集都是不同的,而且里面包含重复的训练样本。
(2)如果存在M个特征,则在每个节点分裂的时候,从M中随机选择m个特征维度(m << M),使用这些m个特征维度中最佳特征(最大化信息增益)来分割节点。在森林生长期间,m的值保持不变。
一开始我们提到的随机森林中的“随机”就是指的这里的两个随机性。两个随机性的引入对随机森林的分类性能至关重要。由于它们的引入,使得随机森林不容易陷入过拟合,并且具有很好得抗噪能力(比如:对缺省值不敏感)。
随机森林分类效果(错误率)与两个因素有关:
- 森林中任意两棵树的相关性:相关性越大,错误率越大;(弱分类器应该good且different)
- 森林中每棵树的分类能力:每棵树的分类能力越强,整个森林的错误率越低。(弱分类器应该good且different)
减小特征选择个数m,树的相关性和分类能力也会相应的降低;增大m,两者也会随之增大。所以关键问题是如何选择最优的m,这也是随机森林的一个重要参数。
OOB (袋外错误率)
上面我们提到,构建随机森林的关键问题就是如何选择最优的特征数m这个参数,要解决这个问题主要依据计算袋外错误率OOB error(out-of-bag error)。
随机森林有一个重要的优点就是,没有必要对它进行交叉验证或者用一个独立的测试集来获得误差的一个无偏估计。它可以在内部进行评估,也就是说在生成的过程中就可以对误差建立一个无偏估计。
我们知道,在构建每棵树时,我们对训练集使用了不同的bootstrap sample(随机且有放回地抽取)。所以对于每棵树而言(假设对于第k棵树),大约有1/3的训练实例没有参与第k棵树的生成,它们称为第k棵树的oob样本。而这样的采样特点就允许我们进行oob估计,它的计算方式如下:
- 对每个样本,计算它作为oob样本的树对它的分类情况(约1/3的树);
- 然后以简单多数投票作为该样本的分类结果;
- 最后用误分个数占样本总数的比率作为随机森林的oob误分率。
oob误分率是随机森林泛化误差的一个无偏估计,它的结果近似于需要大量计算的k折交叉验证。这样,就可以通过比较oob误分率来选择一个最好的特征数m。
随机森林参数
在scikit-learn中,RF的分类器是RandomForestClassifier,回归器是RandomForestRegressor。RF的参数也包括两部分,第一部分是Bagging框架的参数,第二部分是一棵CART决策树的参数。
(1)导入数据
(2)创建随机森林分类器
(3)结果分析
(4) 绘图
(5)随机森林中决策树棵数对性能的影响
2.代码
%% I. 清空环境变量
clear all
clc
warning off
%% II. 导入数据
load data.mat
%%
% 1. 随机产生训练集/测试集
a = randperm(569);
Train = data(a(1:500),:);
Test = data(a(501:end),:);
%%
% 2. 训练数据
P_train = Train(:,3:end);
T_train = Train(:,2);
%%
% 3. 测试数据
P_test = Test(:,3:end);
T_test = Test(:,2);
%% III. 创建随机森林分类器
model = classRF_train(P_train,T_train);
%% IV. 仿真测试
[T_sim,votes] = classRF_predict(P_test,model);
%% V. 结果分析
count_B = length(find(T_train == 1));
count_M = length(find(T_train == 2));
total_B = length(find(data(:,2) == 1));
total_M = length(find(data(:,2) == 2));
number_B = length(find(T_test == 1));
number_M = length(find(T_test == 2));
number_B_sim = length(find(T_sim == 1 & T_test == 1));
number_M_sim = length(find(T_sim == 2 & T_test == 2));
disp(['病例总数:' num2str(569)...
' 良性:' num2str(total_B)...
' 恶性:' num2str(total_M)]);
disp(['训练集病例总数:' num2str(500)...
' 良性:' num2str(count_B)...
' 恶性:' num2str(count_M)]);
disp(['测试集病例总数:' num2str(69)...
' 良性:' num2str(number_B)...
' 恶性:' num2str(number_M)]);
disp(['良性乳腺肿瘤确诊:' num2str(number_B_sim)...
' 误诊:' num2str(number_B - number_B_sim)...
' 确诊率p1=' num2str(number_B_sim/number_B*100) '%']);
disp(['恶性乳腺肿瘤确诊:' num2str(number_M_sim)...
' 误诊:' num2str(number_M - number_M_sim)...
' 确诊率p2=' num2str(number_M_sim/number_M*100) '%']);
%% VI. 绘图
figure
index = find(T_sim ~= T_test);
plot(votes(index,1),votes(index,2),'r*')
hold on
index = find(T_sim == T_test);
plot(votes(index,1),votes(index,2),'bo')
hold on
legend('错误分类样本','正确分类样本')
plot(0:500,500:-1:0,'r-.')
hold on
plot(0:500,0:500,'r-.')
hold on
line([100 400 400 100 100],[100 100 400 400 100])
xlabel('输出为类别1的决策树棵数')
ylabel('输出为类别2的决策树棵数')
title('随机森林分类器性能分析')
%% VII. 随机森林中决策树棵数对性能的影响
Accuracy = zeros(1,20);
for i = 50:50:1000 %模拟从50棵树到1000棵树的一个结果,每次增加50棵 i
%每种情况,运行100次,取平均值
accuracy = zeros(1,100);
for k = 1:100
% 创建随机森林
model = classRF_train(P_train,T_train,i);
% 仿真测试
T_sim = classRF_predict(P_test,model);
accuracy(k) = length(find(T_sim == T_test)) / length(T_test);
end
Accuracy(i/50) = mean(accuracy);
end
%% 1960009019 l13299109228
% 1. 绘图
figure
plot(50:50:1000,Accuracy)
xlabel('随机森林中决策树棵数')
ylabel('分类正确率')
title('随机森林中决策树棵数对性能的影响')
3.运行结果