了解Spark RandomForest featureImportances结果

时间:2016-06-17 09:54:20

标签: apache-spark classification random-forest apache-spark-mllib

我使用RandomForest.featureImportances但我不理解输出结果。

我有12个功能,这是我得到的输出。

我知道这可能不是一个特定于apache-spark的问题,但我无法找到解释输出的任何地方。

// org.apache.spark.mllib.linalg.Vector = (12,[0,1,2,3,4,5,6,7,8,9,10,11],
 [0.1956128039688559,0.06863606797951556,0.11302128590305296,0.091986700351889,0.03430651625283274,0.05975817050022879,0.06929766152519388,0.052654922125615934,0.06437052114945474,0.1601713590349946,0.0324327322375338,0.057751258970832206])

2 个答案:

答案 0 :(得分:13)

给定树集合模型,RandomForest.featureImportances计算每个要素的重要性

在对Leo Breiman和Adele Cutler的“随机森林”文件中的基尼重要性的解释以及从scikit-learn实施之后,这概括了“基尼”对其他损失的重要性。

对于树木的收集,包括提升和装袋,Hastie等。建议使用整体中所有树木的单树重要性的平均值。

此功能的重要性计算如下:

  • 树木平均值:
    • 重要性(特征j)=增益的总和(在特征j上分割的节点),其中增益按照通过节点的实例数量来缩放
    • 将树的重要性标准化为1。
  • 将要素重要性向量归一化为1。

参考文献: Hastie, Tibshirani, Friedman. "The Elements of Statistical Learning, 2nd Edition." 2001. - 15.3.2变量重要性第593页。

让我们回到你的重要性载体:

val importanceVector = Vectors.sparse(12,Array(0,1,2,3,4,5,6,7,8,9,10,11), Array(0.1956128039688559,0.06863606797951556,0.11302128590305296,0.091986700351889,0.03430651625283274,0.05975817050022879,0.06929766152519388,0.052654922125615934,0.06437052114945474,0.1601713590349946,0.0324327322375338,0.057751258970832206))

首先,让我们按重要性对这些功能进行排序:

importanceVector.toArray.zipWithIndex
            .map(_.swap)
            .sortBy(-_._2)
            .foreach(x => println(x._1 + " -> " + x._2))
// 0 -> 0.1956128039688559
// 9 -> 0.1601713590349946
// 2 -> 0.11302128590305296
// 3 -> 0.091986700351889
// 6 -> 0.06929766152519388
// 1 -> 0.06863606797951556
// 8 -> 0.06437052114945474
// 5 -> 0.05975817050022879
// 11 -> 0.057751258970832206
// 7 -> 0.052654922125615934
// 4 -> 0.03430651625283274
// 10 -> 0.0324327322375338

那是什么意思?

这意味着您的第一个特征(索引0)是最重要的特征,权重为~0.19,而您的第11个(索引10)特征在您的模型中最不重要。

答案 1 :(得分:2)

添加到上一个答案:

我遇到的一个问题是以(featureName,Importance)的形式转储结果,因为csv.One可以获取功能输入向量的元数据

 val featureMetadata = predictions.schema("features").metadata

这是此元数据的json结构:

{
"ml_attr": {
              "attrs":
                  {"numeric":[{idx:I,name:N},...],
                   "nominal":[{vals:V,idx:I,name:N},...]},
                   "num_attrs":#Attr
                   }
            }
}            

提取重要性的代码:

val attrs =featureMetadata.getMetadata("ml_attr").getMetadata("attrs")
val f: (Metadata) => (Long,String) = (m => (m.getLong("idx"), m.getString("name")))
val nominalFeatures= attrs.getMetadataArray("nominal").map(f)
val numericFeatures = attrs.getMetadataArray("numeric").map(f)
val features = (numericFeatures ++ nominalFeatures).sortBy(_._1)

val fImportance = pipeline.stages.filter(_.uid.startsWith("rfc")).head.asInstanceOf[RandomForestClassificationModel].featureImportances.toArray.zip(features).map(x=>(x._2._2,x._1)).sortBy(-_._2)

//Save It now
sc.parallelize(fImportance.toSeq, 1).map(x => s"${x._1},${x._2}").saveAsTextFile(fPath)