Apache spark 派斯帕克公司;MLLib:随机森林预测的类概率

Apache spark 派斯帕克公司;MLLib:随机森林预测的类概率,apache-spark,pyspark,random-forest,apache-spark-mllib,Apache Spark,Pyspark,Random Forest,Apache Spark Mllib,我试图提取我使用PySpark训练的随机森林对象的类概率。然而,我在文档的任何地方都没有看到它的例子,它也不是一种RandomForestModel方法 如何从PySpark中的RandomForestModel分类器中提取类概率 以下是文档中提供的示例代码,它只提供了最终类(而不是概率): 我没有看到任何模型。predict_proba()方法--我应该怎么做???据我所知,当前版本(1.2.1)不支持这种方法。本机Scala代码(tree.py)上的Python包装器只定义了“predict

我试图提取我使用PySpark训练的随机森林对象的类概率。然而,我在文档的任何地方都没有看到它的例子,它也不是一种
RandomForestModel
方法

如何从PySpark中的
RandomForestModel
分类器中提取类概率

以下是文档中提供的示例代码,它只提供了最终类(而不是概率):


我没有看到任何
模型。predict_proba()
方法--我应该怎么做???

据我所知,当前版本(1.2.1)不支持这种方法。本机Scala代码(tree.py)上的Python包装器只定义了“predict”函数,这些函数反过来调用相应的Scala对应项(treeEnsembleModels.Scala)。后者通过在二元决策中投票来做出决策。一个更干净的解决方案是提供一个概率预测,该预测可以任意设置阈值,或用于类似sklearn的ROC计算。应在将来的版本中添加此功能

作为一种变通方法,我将predict_proba实现为一个纯Python函数(参见下面的示例)。它既不优雅,也不是非常高效,因为它在森林中的一组单独的决策树上运行一个循环。诀窍——或者说是一个肮脏的黑客——是访问Java决策树模型数组,并将它们转换为Python对应模型。之后,您可以计算整个数据集上各个模型的预测,并使用“zip”在RDD中累积它们的总和。除以树的数量得到所需的结果。对于大型数据集,主节点中少量决策树上的循环应该是可以接受的

由于将Python集成到Spark(在Java中运行)的困难,下面的代码相当棘手。应该非常小心,不要将任何复杂的数据发送到工作节点,这会由于序列化问题而导致崩溃。不能在工作节点上运行引用Spark上下文的代码。此外,不能序列化引用任何Java代码的代码。例如,在下面的代码中,使用len(trees)而不是ntrees可能很诱人-bang!在Java/Scala中编写这样的包装可以更加优雅,例如通过在工作节点上的决策树上运行循环,从而降低通信成本

下面的测试函数表明,predict_proba给出的测试误差与原始示例中使用的predict相同

def predict_proba(rf_model, data):
   '''
   This wrapper overcomes the "binary" nature of predictions in the native
   RandomForestModel. 
   '''

    # Collect the individual decision tree models by calling the underlying
    # Java model. These are returned as JavaArray defined by py4j.
    trees = rf_model._java_model.trees()
    ntrees = rf_model.numTrees()
    scores = DecisionTreeModel(trees[0]).predict(data.map(lambda x: x.features))

    # For each decision tree, apply its prediction to the entire dataset and
    # accumulate the results using 'zip'.
    for i in range(1,ntrees):
        dtm = DecisionTreeModel(trees[i])
        scores = scores.zip(dtm.predict(data.map(lambda x: x.features)))
        scores = scores.map(lambda x: x[0] + x[1])

    # Divide the accumulated scores over the number of trees
    return scores.map(lambda x: x/ntrees)

def testError(lap):
    testErr = lap.filter(lambda (v, p): v != p).count() / float(testData.count())
    print('Test Error = ' + str(testErr))


def testClassification(trainingData, testData):

    model = RandomForest.trainClassifier(trainingData, numClasses=2,
                                         categoricalFeaturesInfo={},
                                         numTrees=50, maxDepth=30)

    # Compute test error by thresholding probabilistic predictions
    threshold = 0.5
    scores = predict_proba(model,testData)
    pred = scores.map(lambda x: 0 if x < threshold else 1)
    lab_pred = testData.map(lambda lp: lp.label).zip(pred)
    testError(lab_pred)

    # Compute test error by comparing binary predictions
    predictions = model.predict(testData.map(lambda x: x.features))
    labelsAndPredictions = testData.map(lambda lp: lp.label).zip(predictions)
    testError(labelsAndPredictions)
def预测概率(rf模型,数据):
'''
此包装器克服了本机语言中预测的“二进制”性质
随机森林模型。
'''
#通过调用底层
#Java模型。它们以py4j定义的JavaArray的形式返回。
trees=rf\u model.\u java\u model.trees()
ntrees=rf_model.numTrees()
分数=决策树模型(树[0])。预测(data.map(lambda x:x.features))
#对于每个决策树,将其预测应用于整个数据集并
#使用“zip”累积结果。
对于范围内的i(1,ntrees):
dtm=决策树模型(树[i])
scores=scores.zip(dtm.predict(data.map(lambda x:x.features)))
分数=分数.map(λx:x[0]+x[1])
#将累积分数除以树的数量
返回分数.map(λx:x/ntrees)
def测试仪错误(圈):
testErr=lap.filter(lambda(v,p):v!=p.count()/float(testData.count())
打印('testerror='+str(testErr))
def测试分类(培训数据、测试数据):
模型=RandomForest.trainClassifier(trainingData,numClass=2,
类别特征信息={},
numTrees=50,maxDepth=30)
#通过阈值概率预测计算测试误差
阈值=0.5
分数=预测概率(模型、测试数据)
pred=scores.map(如果x<阈值1,则λx:0)
lab_pred=testData.map(lambda lp:lp.label).zip(pred)
测试仪错误(实验室预测试)
#通过比较二进制预测计算测试误差
预测=model.predict(testData.map(lambda x:x.features))
labelsAndPredictions=testData.map(lambda lp:lp.label).zip(预测)
测试仪错误(标签和预测)

总而言之,这是学习Spark的一个很好的练习

但是,它将与Spark 1.5.0和新的Spark ML API一起提供。

现在可以使用

Spark ML提供:

  • 包含预测标签的预测列
  • 还有一个
    概率COL
    ,它包含每个标签的概率向量,这就是您要查找的
  • 您还可以访问原始计数
有关更多详细信息,请参阅Spark文档:

也许人们会继续写这篇文章,但今天我在尝试根据训练集计算多类分类器的准确度时遇到了同样的问题。所以我想如果有人尝试使用mllib,我会分享我的经验

概率的计算相当简单,如下所示:-

# say you have a testset against which you want to run your classifier
   (trainingset, testset) =data.randomSplit([0.7, 0.3])
   # I converted the spark dataset containing the test data to pandas
     ptd=testData.toPandas()

   #Now get a count of number of labels matching the predictions

   correct = ((ptd.label-1) == (predictions)).sum() 
   # here we had to change the labels from 0-9 as opposed to 1-10 since
   #labels take the values from 0 .. numClasses-1

   m=ptd.shape[0]
   print((correct/m)*100)

谢谢看起来不错,但您的概率与我们在(二进制)响应功能上运行
RandomForest.trainRegressor()
并将模型中的预测作为概率时不同。从概念上讲,你的方法是怎样的,只是回归输出不同?我没有考虑过,也没有使用随机森林来回归。对于分类,我们可以将肯定类的投票分数解释为概率,这正是我的代码所做的。我不知道回归的概率预测是如何计算的。最近,有一个带有scala解决方案的fork:这个问题现在已经(大部分)在新的Spark ML库中得到了解决:事实上,请参见这里的示例:
# say you have a testset against which you want to run your classifier
   (trainingset, testset) =data.randomSplit([0.7, 0.3])
   # I converted the spark dataset containing the test data to pandas
     ptd=testData.toPandas()

   #Now get a count of number of labels matching the predictions

   correct = ((ptd.label-1) == (predictions)).sum() 
   # here we had to change the labels from 0-9 as opposed to 1-10 since
   #labels take the values from 0 .. numClasses-1

   m=ptd.shape[0]
   print((correct/m)*100)