2015-03-02 8 views
8

Sto tentando di estrarre le probabilità di classe di un oggetto foresta casuale che ho formato utilizzando PySpark. Tuttavia, non vedo un esempio in alcun punto della documentazione, né è un metodo di RandomForestModel.PySpark & ​​MLLib: Probabilità di classe di previsioni di foresta casuale

Come posso estrarre le probabilità di classe da un classificatore RandomForestModel in PySpark?

Ecco il codice di esempio fornito nella documentazione che fornisce solo la classe finale (non la probabilità):

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

non vedo alcun metodo model.predict_proba() - cosa devo fare ??

+0

tardi, ma c'è un bivio con una soluzione di scala: https: //github.com/apache/spark/compare/master...mqk:master –

+0

Il problema è stato (per lo più) risolto nella nuova libreria Spark ML: https://stackoverflow.com/questions/43631031/pyspark- how-to-get-classification-probabilities-from-multilayerperceptronclassi/43643426 # 43643426 – desertnaut

risposta

9

Per quanto posso dire questo non è supportato nella versione corrente (1.2.1). Il wrapper Python sul codice nativo di Scala (tree.py) definisce solo le funzioni 'prevedi' che, a loro volta, chiamano le rispettive controparti Scala (treeEnsembleModels.scala). Questi ultimi prendono le decisioni prendendo un voto tra le decisioni binarie. Una soluzione molto più pulita sarebbe stata quella di fornire una previsione probabilistica che può essere saggiata arbitrariamente o utilizzata per il calcolo dei ROC come in sklearn. Questa funzione dovrebbe essere aggiunta per le versioni future!

Come soluzione temporanea, ho implementato predict_proba come una pura funzione Python (vedi esempio sotto). Non è né elegante né molto efficiente, poiché esegue un ciclo sul set di alberi decisionali individuali in una foresta. Il trucco - o meglio un trucco sporco - è di accedere alla matrice di modelli di alberi decisionali Java e convertirli in controparti Python. Successivamente è possibile calcolare le previsioni del modello individuale sull'intero set di dati e accumulare la somma in un RDD utilizzando "zip". Dividere per il numero di alberi ottiene il risultato desiderato. Per dataset di grandi dimensioni, un loop su un piccolo numero di alberi decisionali in un nodo master dovrebbe essere accettabile.

Il codice riportato di seguito è piuttosto complicato a causa delle difficoltà di integrazione di Python in Spark (eseguito in Java). Si dovrebbe fare molta attenzione a non inviare dati complessi ai nodi worker, il che si traduce in arresti anomali dovuti a problemi di serializzazione. Nessun codice riferito al contesto Spark può essere eseguito su un nodo worker. Inoltre, nessun codice che fa riferimento a qualsiasi codice Java può essere serializzato. Ad esempio, potrebbe essere allettante usare len (alberi) invece di ntrees nel codice sottostante - bang! Scrivere un wrapper simile in Java/Scala può essere molto più elegante, ad esempio eseguendo un ciclo su alberi decisionali su nodi worker e quindi riducendo i costi di comunicazione.

La funzione di test seguente dimostra che il predict_proba fornisce un errore di test identico a quello previsto negli esempi originali.

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) 

Nel complesso, questo è stato un buon esercizio per imparare Spark!

+0

Grazie. Sembra buono, ma le tue probabilità sono diverse da quando eseguiamo 'RandomForest.trainRegressor()' sulla funzione di risposta (binaria) e prendiamo le previsioni dal modello come probabilità. Concettualmente, qual è il tuo metodo e stai semplicemente prendendo l'uscita di regressione diversa? – Bryan

+0

Non ho considerato e non ho usato foreste casuali per la regressione. Per la classificazione si può interpretare banalmente la frazione di voti per la classe positiva come probabilità, e questo è esattamente ciò che fa il mio codice. Non so come la previsione probabilistica sia calcolata per la regressione. –

1

Sarà comunque disponibile con Spark 1.5.0 e la nuova API Spark-ML.

4

Questo è ora disponibile.

Spark ML prevede:

  • un predictionCol che contiene il predetto etichetta
  • e probabilityCol che contiene un vettore con le probabilità per ciascuna etichetta, questo è ciò che tu dove cerchi!
  • È possibile anche accedere ai conteggi

Per maggiori dettagli, qui è la documentazione Spark: http://spark.apache.org/docs/latest/ml-classification-regression.html#output-columns-predictions

+0

Infatti, vedere qui per un esempio: http://stackoverflow.com/questions/43631031/pyspark-how-to-get-classification-probabilities-from-multilayerperceptronclassi/43643426 – desertnaut

0

Probabilmente la gente avrebbe spostato con questo post, ma sono stato colpito dallo stesso problema oggi quando si tenta di calcolare l'accuratezza del classificatore multi-classe rispetto a un set di allenamento. Così ho pensato che condividere la mia esperienza, se qualcuno sta cercando con mllib ...

probabilità può essere calcolata abbastanza facile come segue: -

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