PySpark和MLLib:随机森林特征重要性

17

我正在尝试使用PySpark提取已训练的随机森林对象的特征重要性。然而,在文档中我没有看到任何实现此操作的例子,而且RandomForestModel也没有相应的方法。

我该如何从 PySpark 中的RandomForestModel回归器或分类器中提取特征重要性呢?下面是文档中提供的示例代码,但其中并没有提到特征重要性。

from pyspark.mllib.tree import RandomForest
from pyspark.mllib.util import MLUtils

# Load and parse the data file into an RDD of LabeledPoint.
data = MLUtils.loadLibSVMFile(sc, 'data/mllib/sample_libsvm_data.txt')
# Split the data into training and test sets (30% held out for testing)
(trainingData, testData) = data.randomSplit([0.7, 0.3])

# Train a RandomForest model.
#  Empty categoricalFeaturesInfo indicates all features are continuous.
#  Note: Use larger numTrees in practice.
#  Setting featureSubsetStrategy="auto" lets the algorithm choose.
model = RandomForest.trainClassifier(trainingData, numClasses=2, categoricalFeaturesInfo={},
                                     numTrees=3, featureSubsetStrategy="auto",
                                     impurity='gini', maxDepth=4, maxBins=32)

我找不到model.__featureImportances_属性 -- 我应该在哪里查找?


有人对这个问题有更新吗?现在是否有PySpark实现可以实现model._featureImportances - Pablo O
1
@PabloO 我已经发布了一个带有更新的答案。 - titiro89
5个回答

18

版本升级至2.0.0以上的更新

从版本2.0.0开始,可以在随机森林(Random Forest)中找到FeatureImportances,如此处所示

实际上,您可以在此处发现以下内容:

DataFrame API支持两种主要的树集成算法:随机森林和梯度提升树(GBTs)。两者都使用spark.ml决策树作为其基本模型。

用户可以在MLlib Ensemble指南中找到有关集成算法的更多信息。 在本节中,我们演示了DataFrame API的用法。

这个API与原始MLlib集成API之间的主要区别是:

  • 支持DataFrames和ML流水线
  • 分类与回归分离
  • 使用DataFrame元数据来区分连续和分类特征
  • 随机森林的更多功能:估计特征重要性,以及用于分类的每个类别的预测概率(也称为类条件概率)。

如果您想要Feature Importance值,则必须使用ml包而不是mllib,并使用数据框(DataFrames)。

下面是一个示例,您可以在此处找到:

# IMPORT
>>> import numpy
>>> from numpy import allclose
>>> from pyspark.ml.linalg import Vectors
>>> from pyspark.ml.feature import StringIndexer
>>> from pyspark.ml.classification import RandomForestClassifier

# PREPARE DATA
>>> df = spark.createDataFrame([
...     (1.0, Vectors.dense(1.0)),
...     (0.0, Vectors.sparse(1, [], []))], ["label", "features"])
>>> stringIndexer = StringIndexer(inputCol="label", outputCol="indexed")
>>> si_model = stringIndexer.fit(df)
>>> td = si_model.transform(df)

# BUILD THE MODEL
>>> rf = RandomForestClassifier(numTrees=3, maxDepth=2, labelCol="indexed", seed=42)
>>> model = rf.fit(td)

# FEATURE IMPORTANCES
>>> model.featureImportances
SparseVector(1, {0: 1.0}) 

如果您需要使用原始特征名称的featureImportances,请使用以下链接:https://www.timlrx.com/2018/06/19/feature-selection-using-feature-importance-score-creating-a-pyspark-estimator/ - Gigi

6
我很抱歉要让你失望,但在MLlib中实现的随机森林模型中,特征重要性并没有被计算出来,因此除非你自己实现它们的计算,否则你无法从任何地方获取它们。
以下是查找方法:
你需要调用一个在这里定义的函数RandomForest.trainClassifierhttps://github.com/apache/spark/blob/branch-1.3/python/pyspark/mllib/tree.py 它会调用callMLlibFunc("trainRandomForestModel", ...)函数,这是调用Scala函数RandomForest.trainClassifierRandomForest.trainRegressor(取决于算法)的语句,并返回RandomForestModel对象。
该对象在https://github.com/apache/spark/blob/branch-1.3/mllib/src/main/scala/org/apache/spark/mllib/tree/model/treeEnsembleModels.scala中有描述,并扩展了同一源文件中定义的TreeEnsembleModel。不幸的是,该类仅存储了算法(回归或分类)、树本身、树的相对权重和组合策略(和或平均或选举)。不幸的是,它不存储特征重要性,甚至不会计算它们(有关计算算法,请参见https://github.com/apache/spark/blob/branch-1.3/mllib/src/main/scala/org/apache/spark/mllib/tree/RandomForest.scala

1
如果您选择通过自己实现功能来为MLlib做出贡献,可以使用sklearn的实现。https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/ensemble/forest.py - 方法feature_importances_收集基础树的特征重要性,并通过计算平均值将它们分组在一起。从这里获取的代码 - https://github.com/scikit-learn/scikit-learn/blob/f6af4881a5a66fb21688379b39f9304898a11bc0/sklearn/tree/_tree.pyx - 方法compute_feature_importances用于估计单个树的特征重要性。 - 0x0FFF
谢谢 - 是的,我们正在尝试类似的东西,但由于我们只有树形调试输出(而不是每个特征分裂的不纯度减少),因此我们只能对重要性进行粗略估计。是否有一种方法可以从每个MLLib树分裂中获得不纯度的减少? - Bryan
你在这里唯一能做的就是通过将估算决策树特征重要性的代码移植到Scala并将此补丁推送到MLlib代码来为MLlib做出贡献。如果没有这个,你的估算只会是粗略的,正如你所提到的。 - 0x0FFF

3

Spark 1.5现已实现了特征重要性的功能。查看已解决的JIRA问题。您可以使用以下代码获取特征重要性的向量:

val importances: Vector = model.featureImportances

这实际上只是在Scala端,还没有在PySpark中。也许下一个版本会有。 - j_houg
1
此外,它只存在于ML实现中,而不在MLlib中。 - Pop

3
现在在Spark ML中似乎有一种简单的方法来实现这个。请参见https://kb.databricks.com/machine-learning/extract-feature-info.html
这是关键代码:
pipeline = Pipeline(stages=[indexer, assembler, decision_tree)
DTmodel = pipeline.fit(train)
va = dtModel.stages[-2]
tree = DTmodel.stages[-1]

display(tree) #visualize the decision tree model
print(tree.toDebugString) #print the nodes of the decision tree model

list(zip(va.getInputCols(), tree.featureImportances))

2

我相信现在这个已经可以运行了。你可以调用:

from pyspark.ml.classification import RandomForestClassifier
rf = RandomForestClassifier()
model = rf.fit(data)
print model.featureImportances

在随机森林分类器上运行fit操作会返回一个RandomForestClassificationModel,其中已经计算出了所需的featureImportances。希望这可以帮到你:)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接