2015-03-02 16 views
8

Ich versuche, die Klassenwahrscheinlichkeiten eines zufälligen Waldobjekts zu extrahieren, das ich mit PySpark trainiert habe. Ich sehe jedoch nirgendwo in der Dokumentation ein Beispiel dafür, und es ist auch keine Methode von RandomForestModel.PySpark & ​​MLLib: Klassenwahrscheinlichkeiten von zufälligen Waldvorhersagen

Wie kann ich Klassenwahrscheinlichkeiten aus einem RandomForestModel Klassifikator in PySpark extrahieren?

Hier ist der Beispielcode in der Dokumentation, die nur die letzte Klasse bietet (nicht die Wahrscheinlichkeit):

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) 

# Evaluate model on test instances and compute test error 
predictions = model.predict(testData.map(lambda x: x.features)) 

ich jede model.predict_proba() Methode nicht sehen - was soll ich tun ??

+0

spät, aber es gibt eine Gabel mit einer scala Lösung: https: //github.com/apache/spark/compare/master...mqk:master –

+0

die Frage jetzt war (meist) in der neuen Spark-ML-Bibliothek aufgelöst: https://stackoverflow.com/questions/43631031/pyspark- how-to-get-Klassifizierung-Wahrscheinlichkeiten-from-Multilayerperceptronclassi/43643426 # 43643426 – desertnaut

Antwort

9

Soweit ich das beurteilen kann, wird dies in der aktuellen Version (1.2.1) nicht unterstützt. Der Python-Wrapper über den nativen Scala-Code (tree.py) definiert nur "vorhergesagte" Funktionen, die wiederum die entsprechenden Scala-Gegenstücke (treeEnsembleModels.scala) aufrufen. Letztere treffen Entscheidungen, indem sie unter binären Entscheidungen abstimmen. Eine viel sauberere Lösung wäre gewesen, eine probabilistische Vorhersage zu liefern, die beliebig für die ROC-Berechnung wie in sklearn beliebig schwellenfrei oder für die ROC-Berechnung verwendet werden kann. Diese Funktion sollte für zukünftige Versionen hinzugefügt werden!

Als Workaround habe ich predict_proba als reine Python-Funktion implementiert (siehe Beispiel unten). Es ist weder elegant noch sehr effizient, da es eine Schleife über die Menge der einzelnen Entscheidungsbäume in einem Wald führt. Der Trick - oder eher ein schmutziger Hack - besteht darin, auf das Array von Java-Entscheidungsbaummodellen zuzugreifen und sie in Python-Gegenstücke zu werfen. Danach können Sie die Vorhersagen eines einzelnen Modells über den gesamten Datensatz berechnen und ihre Summe in einer RDD mit 'zip' akkumulieren. Das Teilen nach der Anzahl der Bäume bringt das gewünschte Ergebnis. Bei großen Datenmengen sollte eine Schleife über eine kleine Anzahl von Entscheidungsbäumen in einem Master-Knoten akzeptabel sein.

Der folgende Code ist ziemlich schwierig wegen der Schwierigkeiten bei der Integration von Python in Spark (ausgeführt in Java). Man sollte sehr vorsichtig sein, keine komplexen Daten an Arbeiterknoten zu senden, was zu Abstürzen aufgrund von Serialisierungsproblemen führt. Kein Code, der sich auf den Spark-Kontext bezieht, kann auf einem Worker-Knoten ausgeführt werden. Auch kein Code, der sich auf irgendeinen Java-Code bezieht, kann serialisiert werden. Zum Beispiel könnte es verlockend sein, len (trees) anstelle von ntrees im folgenden Code zu verwenden - bang! Das Schreiben eines solchen Wrappers in Java/Scala kann viel eleganter sein, zum Beispiel indem eine Schleife über Entscheidungsbäume auf Arbeiterknoten ausgeführt wird und somit die Kommunikationskosten reduziert werden.

Die folgende Testfunktion zeigt, dass die Vorhersagefunktion einen identischen Testfehler liefert, wie er in den ursprünglichen Beispielen verwendet wurde.

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) 

Alles in allem war dies eine schöne Übung, um Spark zu lernen!

+0

Danke. Es sieht gut aus, aber Ihre Wahrscheinlichkeiten sind anders als wenn wir 'RandomForest.trainRegressor()' auf der (binären) Antwortfunktion ausführen und die Vorhersagen aus dem Modell als Wahrscheinlichkeiten annehmen. Konzeptionell, wie ist Ihre Methode und nur die Regressionsausgabe unterschiedlich? – Bryan

+0

Ich habe keine zufälligen Gesamtstrukturen für die Regression berücksichtigt und nicht verwendet. Zur Klassifizierung kann man den Stimmenanteil der positiven Klasse als Wahrscheinlichkeit trivial interpretieren, und genau das ist mein Code. Ich weiß nicht, wie die probabilistische Vorhersage für die Regression berechnet wird. –

1

Es wird jedoch mit Spark 1.5.0 und der neuen Spark-ML-API verfügbar sein.

4

Dies ist jetzt verfügbar.

Funken ML bietet:

  • a predictionCol dass die Etikett vorausgesagten enthält
  • und einen probabilityCol, die für jedes Etikett einen Vektor mit den Wahrscheinlichkeiten enthält, das ist, was Sie suchen nach!
  • Sie auch

Für weitere Details zu den Rohzählungen zugreifen können, hier ist die Spark-Dokumentation: http://spark.apache.org/docs/latest/ml-classification-regression.html#output-columns-predictions

+0

Tat - hier für ein Beispiel siehe: http://stackoverflow.com/questions/43631031/pyspark-how-to-get-classification-probabilities-from-multilayerperceptronclassi/43643426 – desertnaut

0

mit diesem Post bewegten auf Wahrscheinlich hätten Menschen, aber ich wurde mit dem gleichen Problem betroffen heute beim Versuch, die Genauigkeit für den Mehrklassen-Klassifikator gegen ein Trainingssatz zu berechnen. Also dachte ich, ich meine Erfahrung teilen, wenn jemand mit mllib versuchen ...

Wahrscheinlichkeit berechnet werden kann ziemlich einfach, wie folgt: -

# 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)