前言

最近阅读了spark mllib(版本:spark 1.3)中Random Forest的实现,发现在分布式的数据结构上实现迭代算法时,有些地方与单机环境不一样。单机上一些直观的操作(递归),在分布式数据上,必须进行优化,否则I/O(网络,磁盘)会消耗大量时间。本文整理spark随机森林实现中的相关技巧,方便后面回顾。

 

随机森林算法概要

随机森林算法的详细实现和细节,可以参考论文Breiman 2001。这里简单说说大体思路,方便理解代码。

随机森林是一个组装(ensemble model)模型,内部的模型使用决策树。基本思想是生成很多很多决策树(构成森林),最后由这些决策数一起投票决定最终结果。生成树的过程中,从行和列两个方向添加随机过程。行方向,在构建每棵树前,使用有放回抽样(称为Bootstrapping),得到训练数据。列方向,每次选择切分点时,对feature进行无放回随机抽样,得到一个feature子集,在当前节点上,只使用这些子集对应的数据计算最优切分点。这也是为什么此算法称为随机森林,是不是很直观。相比于单一决策树,随机森林有以下一些优点:

  1. 结果比较稳定,不容易出现过拟合;
  2. Out-Of-Bag error评估模型效果,无需交叉检验;
  3. 可得到feature重要性。

当然,为了得到上面的优点,必须付出计算开销作为代价。在单机时代,使用随机森林(R或scikit-learn)往往成本很高,但是现在有了spark,使得大规模,分布式迭代计算成为了可能,所以在spark上运用随机森林是技术发展的必然结果!

 

Spark实现优化

spark在实现随机森林时,采用了下面几个优化策略:

  1. 切分点抽样
  2. feature装箱(bin)
  3. 分区统计
  4. 逐层计算(level-wise)

使用这些策略,原因在于RDD的数据时分布在不同服务器上,为了避免过多的I/O,必须在原始算法上做出一些优化,否则执行时间可能难以接受。下面分别详细讨论这三个优化策略。

 

切分点抽样

此优化主要针对连续变量。先回忆一下一般的决策树是如何对连续变量进行切分点选择的。一般是先对feature进行排序,然后选取相邻两个数据之间的点作为切分点。如果在RDD上执行这个操作,不可避免会使用shuffle过程,此过程会带来大量的网络通讯。而且,一般RDD上的数据都很大,少则几百万,多则几亿到几十亿,甚至更多。在这样的数量级上进行排序操作,想想也是醉了。所以,为了避免排序操作,mllib通过抽样的方法,在样本上进行排序,并且根据样本,获取切分点。据spark团队反馈,使用此策略虽然牺牲了部分精度,但是在实际运用过程中,并没有带来过多的影响,模型效果可以接受。

 

feature装箱

根据抽样,得到切分点后,接下来是对feature进行装箱操作,箱子就是由相邻的样本切分点构成。箱子的个数是非常小的,一般实际中采用30个左右。计算每个箱子中不同种类的占比,可以很快计算出最优切分点。

举个例子,参考上面的示例数据,第一行是每个切分点的比例统计。基于上面的数据,可能生成3中切分情况,分别有棕,红和绿色三行表示。如果需要计算棕色的切分情况,只需要按照第一行的组合方式,就可以很快的计算所出来。

 

分区统计

RDD分区中装箱数据单独统计后,可以通过reduce将每个分区的数据合并,得到总体的装箱数据(通过mapPartition实现分区统计)。正是由于装箱统计数据可以合并,所以可以很好的适应分布式数据环境,最后需要合并的数据也只是一些统计数据,不会带来很大的网络通讯开销。

 

逐层计算

单机版本的决策数生成过程是通过递归调用(本质上是深度优先)的方式构造树,在构造树的同事,需要移动数据,将同一个子节点的数据移动到一起。此方法在分布式数据结构上无法有效的执行,而且也无法执行,因为数据太大,无法放在一起,所以在分布式存储。mlib采用的策略是逐层构建树节点(本质上是广度优先),这样遍历所有数据的次数等于所有树的最大层数。每次遍历时,只需要计算每个节点所有feature的装箱统计参数,遍历完后,根据节点装箱统计量,决定是否切分,以及如何切分。

 

以上就是spark mllib实现的随机森林的关键技巧。当然还有很多实现细节这里没有描述,不过如果理解了这些技巧,对阅读spark mllib随机森林源代码会有很大帮助,希望对读者有用。

 

Spark Random Forest实现的不足

截止到spark 1.3,mllib的随机森林仍然不支持OOB error和variable importance的支持,也有一些网友在spark社区咨询此问题,但是目前没有得到官方的回应。希望后面,spark可以支持此特性。

 

应用案例

目前,在网络游戏流失预测的场景下,使用spark随机森林模型(1000棵树)和单机c50模型做了对比试验。试验中覆盖5款不同类型的游戏,共执行608轮,试验周期跨度为4个月。采用了相同的数据,由于单机数据量计算限制,C50使用了10%的采样建模,而spark使用了全量数据(计算能力秒杀)。试验结果是随机森林的模型效果明显优于C50。F1值有37%的提升,而F2(召回率优先)提升度高达72%。

提升可能的原因有两个:

1 随机森林模型效果确实优于C50

2 随机森林建模数据量有质的飞跃,导致性能提升

 

参考资料

  1. Spark源代码
  2. Spark峰会关于分布式决策树实现的分享

Spark随机森林实现学习的更多相关文章

  1. Spark随机森林实战

    package big.data.analyse.ml.randomforest import org.apache.spark.ml.Pipeline import org.apache.spark ...

  2. spark 随机森林算法案例实战

    随机森林算法 由多个决策树构成的森林,算法分类结果由这些决策树投票得到,决策树在生成的过程当中分别在行方向和列方向上添加随机过程,行方向上构建决策树时采用放回抽样(bootstraping)得到训练数 ...

  3. python spark 随机森林入门demo

    class pyspark.mllib.tree.RandomForest[source] Learning algorithm for a random forest model for class ...

  4. Spark随机深林扩展—OOB错误评估和变量权重

    本文目的 当前spark(1.3版)随机森林实现,没有包括OOB错误评估和变量权重计算.而这两个功能在实际工作中比较常用.OOB错误评估可以代替交叉检验,评估模型整体结果,避免交叉检验带来的计算开销. ...

  5. Spark2.0机器学习系列之6:GBDT(梯度提升决策树)、GBDT与随机森林差异、参数调试及Scikit代码分析

    概念梳理 GBDT的别称 GBDT(Gradient Boost Decision Tree),梯度提升决策树.     GBDT这个算法还有一些其他的名字,比如说MART(Multiple Addi ...

  6. 机器学习第5周--炼数成金-----决策树,组合提升算法,bagging和adaboost,随机森林。

    决策树decision tree 什么是决策树输入:学习集输出:分类觃则(决策树) 决策树算法概述 70年代后期至80年代初期,Quinlan开发了ID3算法(迭代的二分器)Quinlan改迚了ID3 ...

  7. 04-10 Bagging和随机森林

    目录 Bagging算法和随机森林 一.Bagging算法和随机森林学习目标 二.Bagging算法原理回顾 三.Bagging算法流程 3.1 输入 3.2 输出 3.3 流程 四.随机森林详解 4 ...

  8. 100天搞定机器学习|Day56 随机森林工作原理及调参实战(信用卡欺诈预测)

    本文是对100天搞定机器学习|Day33-34 随机森林的补充 前文对随机森林的概念.工作原理.使用方法做了简单介绍,并提供了分类和回归的实例. 本期我们重点讲一下: 1.集成学习.Bagging和随 ...

  9. 第七章——集成学习和随机森林(Ensemble Learning and Random Forests)

    俗话说,三个臭皮匠顶个诸葛亮.类似的,如果集成一系列分类器的预测结果,也将会得到由于单个预测期的预测结果.一组预测期称为一个集合(ensemble),因此这一技术被称为集成学习(Ensemble Le ...

随机推荐

  1. win8 下 IIS APPPOOL\DefaultAppPool 登录失败的解决方法

    来源:网络 添加ASP.NET网站时,选择添加"添加应用程序"连接sql server 2005(2008)可能会报始下的错误:(说明:2005必报错,2008选报错)" ...

  2. 关于java中线程休眠的另一种写法

    编辑器加载中... 优先使用TimeUnit类中的sleep() TimeUnit是什么? TimeUnit是java.util.concurrent包下面的一个类,TimeUnit提供了可读性更好的 ...

  3. matlab微分方程dsolve使用

    y=dsolve('Dy=exp(-x-y-2)','y(0)=-2','x') dy/dx 写成Dy (注意大小写) y(0)=-2 表示初始条件 'x'表示积分变量

  4. 产品中 configure/cross compile的一个bug

    在mac机上, 为iPhone版本编译产品. 运行./configure报错如下: configure:22793: error: cannot run test program while cros ...

  5. iOS开发零基础--Swift基础篇--常量&变量的定义

    什么是常量和变量 在Swift中规定:在定义一个标识符时必须明确说明该标识符是一个常量还是变量 使用let来定义常量,定义之后不可以修改 使用var来定义变量,定义之后可以修改 常量和变量的使用注意: ...

  6. Microsoft.Extensions.Options支持什么样的配置类?

    在.Net core中,微软放弃了笨重基于XML的.Config配置文件(好吧,像我这种咸鱼早都忘了如何自己写一个Section了). 现在主推新的高度可扩展的配置文件(参见此处) 对于新的配置系统, ...

  7. NoSQL精粹(NoSQL Distilled)——序言

    之前说到博客长草的问题,想了想除了很忙特别忙非常忙各种瞎忙忙你妹啊外,主要还是不知道写什么好--到这家公司的两年中从JS到领域驱动到缓存服务器从前端到后端各种折腾,有些东西虽然有所心得,不过既然前人已 ...

  8. 递归获取XML元素

    看到的一道题,用递归获取XML元素.... static void Main(string[] args) { string xmlContent = @"<FileSystem> ...

  9. t-sql或mssql怎么用命令行导入数据脚本

    osql简单用法:用来将本地脚本执行,适合sql脚本比较大点的情况,执行起来比较方便 osql -S serverIP -U sa -P 123 -i C:\script.sql serverIP数据 ...

  10. 团队项目——站立会议 DAY1

    团队项目--站立会议 DAY1        团队成员介绍(5人):张靖颜.何玥.钟灵毓秀.赵莹.王梓萱        今日(2016/5/6)为站立会议的第一天,一起对团队项目进行讨论,并对每个人的 ...