opencv2.4.9中随机森林学习

来源:互联网 发布:山西软件定做开发 编辑:程序博客网 时间:2024/05/17 06:31

Introduction

forest作为计算机领域术语是器学习先驱者,分类回归树作者之一,Bagging方法发明者Leo Breiman提出的,Random forest algorithm是由Leo Breiman and Adele Cutler 2001年提出的,用来做分类、回归或其他任务,但是Random forest这个词1963年在The distance method for estimating densities中就被提出了,还有Poisson Random Forests 一词。随机森林是由许多决策树构成的,决策树之间是同等地位关系,如果用数学表达式来描述,就是:这里写图片描述(1),其中B代表决策树的个数,fb就是每个决策树的输出结果,从这个公式中可以看出,对于样本x’的分类或回归值是由B个决策树投票得到的,且各个决策树的投票权值都相同,数学形式跟AdaBoost很像,也是集成学习算法之一。

决策树结构

决策树分类器是多阶段决策方法之一,任何多阶段决策方法都是将一个复杂问题分解为多个简单问题,再简单问题的答案合成复杂问题的答案,即分治思想。
决策树结构[1]如下:
这里写图片描述
每个决策树在分类时都将data space像下面那样用横、竖分成几个小区域,每个区域有个标签,新来一个测试样例,样例落在哪个区域就贴上哪个标签。
这里写图片描述
虽然决策树算法准确率较高,但是往往会出现过拟合等不良现象,即低偏差,高方差( low bias, but very high variance)问题,因此引入随机森林来利用决策树的优点同时避免其不足。

随机森林算法步骤

这里写图片描述
来源:http://article.sapub.org/10.5923.j.algorithms.20130201.02.html#Sec2.2.4

随机森林的训练

    opencv2.4.9中训练随机森林的函数是bool CvRTrees::grow_forest( const CvTermCriteria term_crit ),先根据终止条件term_crit 中的max_iter字段(人为指定)预分配决策树CvForestTree空间,CvForestTree继承自CvDTree,max_iter代表决策树的个数,因此外层while是随机森林的主循环,如果不计算特征的各个变量的重要性,while循环很简洁,在每次循环中只要调用CvForestTree中的train函数即可,得到的决策树保存在CvRTrees的保护成员变量数组指针trees所指内存中。
  1. 样本采样。随机森林在训练时将样本分成训练集和测试集,采用有放回抽样(sampling with
    replacement),大约有三分之一的数据在max_iter此决策树的训练中从来没有被抽到过(证明),称这些数据是oob(out-of-bag),oob数据可以用来做测试集,其余三分之二用来做训练集。每次训练所用的样本都不一样,因此把采样过程放在外层while循环里面,如果输入数据有nsamples个,则每次训练有放回取nsamples个样本。
    rtrees.cpp中CvRTrees::grow_forest中有代码如下:
  cvZero( sample_idx_mask_for_tree );  for(i = 0; i < nsamples; i++ ) //form sample for creation one tree  {      int idx = (*rng)(nsamples);//产生0到nsamples之间均匀分布的随机数      sample_idx_for_tree->data.i[i] = idx;//第i个训练样本的实际编号,真实数据在data变量中     //表示数据是否是训练集,0表示测试集,255表示训练集     sample_idx_mask_for_tree->data.ptr[idx] = 0xFF;  }

2.决策树增长过程。首先将训练集全部放在根结点root中,然后从上到下递归逐渐生成决策树的后代结点,每个父结点分裂成两个子结点,在分裂之前调用calc_node_value函数,它所执行的过程主要是计算如下公式:
无交叉验证时公式
有交叉验证时公式
如果在决策树增长过程中,进行了交叉验证,则还会执行剪枝过程。
如果可以分裂,则会调用find_best_split这个函数,但是执行的不是CvDTree的find_best_split函数,而是CvForestTree的find_best_split函数,这个体现了C++的多态特性,也是为什么CvDTree已经有了一个合适的train函数而CvForestTree还要继续重新封装CvDTree的原因之一吧。

3.特征子集选择。关于特征,补充一点知识。X is called an ordered or numerical pattern if its features take values from an ordered set, and categorical if its features take values from a set not having a natural ordering.Ordered or numerical features can have either discrete or continuous values.
CvForestTree::find_best_split中随机地交换特征两个分量的mask值,一开始的active_var_mask可以人工输入,比如为4,输入active_var_mask的个数不能超过特征的维数。这个find_best_split比较复杂,后续更新再分析。
关于random forest的原始文献中提到,随机森林的错误率依赖于两个因素:一是森林中任意两个决策树之间的相关性;二是每棵决策树的分类回归能力。任意两棵数之间的相关性越强,则总错误率越高,每个决策树的能力越强,则总错误率越低。然而这两个因素是有关系的,通过特征子集大小m联系起来,m越大决策树之间越相关但是每棵数的能力增加了,m越小则决策树之间关系变弱了但每棵决策树的分类回归能力降低了。因此随机森林对这个变量子集大小很敏感,为了保证总的错误率达到最小,理论上可以通过计算obb错误率(袋外错误率)来选择合适的m。

4.变量的重要性。变量的重要性可以为决策提供参考,比如在卖东西时,考虑顾客是否购买,会对顾客的现金数、喜好、商品的数量、服务态度、天气之类这些特征做个排序,最先关注重要因素然后是次要因素,从而判断顾客是否会购买。特征的重要性可以为特征选择,降维做参考。

使用随机森林分类

采用随机森林进行字符识别,这是个多分类问题,数据来源于opencv2.4.9的samples/cpp/letter-recognition.data文件,一共有20,000行样本,每个样本的特征为16维,每行的第一列为类别,转换成数值。训练集与测试集比例为0.8:0.2。设置变量特征类型为ordered而类别标签为categorical 。训练终止条件由CvRTParams指定,其带参数构造函数:
    CvRTParams( int max_depth, int min_sample_count,                float regression_accuracy, bool use_surrogates,                int max_categories, const float* priors, bool calc_var_importance,                int nactive_vars, int max_num_of_trees_in_the_forest,                float forest_accuracy, int termcrit_type );

max_categories – 用于寻找最佳子分裂时将categorical类型变量聚类个数数上限,即类中心数K,满足这里写图片描述
regression_accuracy-只用于回归,若是分类,设置为0。
priors–用于分错类时的惩罚权值。
nactive_vars–用于find_best_split选择最佳特征子集时确定每个tree node(包括root node)所使用的特征子集大小,如果设置为0,则大小为默认值sqrt(dims),dims是特征的总维数。
max_num_of_trees_in_the_forest–确定等式(1)中B的上限。
源码参照samples/cpp/letter_recog.cpp

随机森林的特点总结

1.
来源

参考文献:
[1]Safavian S R, Landgrebe D. A survey of decision tree classifier methodology[J]. IEEE transactions on systems, man, and cybernetics, 1991, 21(3): 660-674.

转载请注明作者和出处:http://blog.csdn.net/CHIERYU 未经允许请勿用于商业用途

1 0