2016-05-18 18 views
5

È noto che GBT in Spark fornisce le etichette previste sin d'ora.Previsione delle probabilità delle classi in caso di alberi di incremento graduale in Spark utilizzando l'output dell'albero

stavo pensando di provare a calcolare le probabilità previste per una classe (ad esempio tutte le istanze che rientrano sotto una certa foglia)

I codici per la costruzione di GBT

import org.apache.spark.SparkContext 
import org.apache.spark.mllib.regression.LabeledPoint 
import org.apache.spark.mllib.linalg.Vectors 
import org.apache.spark.mllib.tree.GradientBoostedTrees 
import org.apache.spark.mllib.tree.configuration.BoostingStrategy 
import org.apache.spark.mllib.tree.model.GradientBoostedTreesModel 
import org.apache.spark.mllib.util.MLUtils 

//Importing the data 
val data = sc.textFile("data/mllib/credit_approval_2_attr.csv") //using the credit approval data set from UCI machine learning repository 

//Parsing the data 
val parsedData = data.map { line => 
    val parts = line.split(',').map(_.toDouble) 
    LabeledPoint(parts(0), Vectors.dense(parts.tail)) 
} 

//Splitting the data 
val splits = parsedData.randomSplit(Array(0.7, 0.3), seed = 11L) 
val training = splits(0).cache() 
val test = splits(1) 

// Train a GradientBoostedTrees model. 
// The defaultParams for Classification use LogLoss by default. 
val boostingStrategy = BoostingStrategy.defaultParams("Classification") 
boostingStrategy.numIterations = 2 // We can use more iterations in practice. 
boostingStrategy.treeStrategy.numClasses = 2 
boostingStrategy.treeStrategy.maxDepth = 2 
boostingStrategy.treeStrategy.maxBins = 32 
boostingStrategy.treeStrategy.subsamplingRate = 0.5 
boostingStrategy.treeStrategy.maxMemoryInMB =1024 
boostingStrategy.learningRate = 0.1 

// Empty categoricalFeaturesInfo indicates all features are continuous. 
boostingStrategy.treeStrategy.categoricalFeaturesInfo = Map[Int, Int]() 

val model = GradientBoostedTrees.train(training, boostingStrategy) 

model.toDebugString 

Questo mi dà 2 alberi di profondità 2, come di seguito per semplicità:

Tree 0: 
    If (feature 3 <= 2.0) 
    If (feature 2 <= 1.25) 
     Predict: -0.5752212389380531 
    Else (feature 2 > 1.25) 
     Predict: 0.07462686567164178 
    Else (feature 3 > 2.0) 
    If (feature 0 <= 30.17) 
     Predict: 0.7272727272727273 
    Else (feature 0 > 30.17) 
     Predict: 1.0 
    Tree 1: 
    If (feature 5 <= 67.0) 
    If (feature 4 <= 100.0) 
     Predict: 0.5739387416147804 
    Else (feature 4 > 100.0) 
     Predict: -0.550117566730937 
    Else (feature 5 > 67.0) 
    If (feature 2 <= 0.0) 
     Predict: 3.0383669122382835 
    Else (feature 2 > 0.0) 
     Predict: 0.4332824083446489 

la mia domanda è: Posso usare gli alberi sopra per calcolare probabilità previste come:

Rispetto a ogni istanza nel set funzione utilizzato per la previsione

exp (punteggio foglia dal punteggio albero 0 + foglia da albero 1)/(1 + exp (punteggio foglia da albero punteggio 0 + foglia da albero 1))

Questo mi dà una sorta di probabilità. Ma non sono sicuro se sia il modo giusto per farlo. Inoltre, se esiste un documento che spiega come vengono calcolati i punteggi delle foglie (previsione). Sarei davvero grato se qualcuno potesse condividerlo.

Qualsiasi suggerimento sarebbe superbo.

risposta

0

In realtà sono riuscito a prevedere le probabilità utilizzando l'albero e la formulazione dell'albero fornito nella domanda. Ho effettivamente controllato con l'output di etichette previsto GBT. Corrisponde esattamente quando uso la soglia come 0.5.

Quindi facciamo lo stesso con un leggero cambiamento.

Rispetto a ogni istanza nel set funzione utilizzato per la previsione:

exp (punteggio foglia da albero 0 + (learning_rate) * punteggio foglia da albero 1)/(1 + exp (punteggio foglia da albero 0 + (learning_rate) * punteggio partendo dall'albero 1))

Questo essenzialmente mi dà le probabilità previste.

Ho provato lo stesso su 3 alberi con profondità 3. Ha funzionato. E anche con set di dati diversi.

Sarebbe bello sapere se qualcun altro ha già provato questo. In caso contrario, possono provare questo e commentare.

+1

Perché non si incolla qui il codice di calcolo della probabilità. Ciò aiuterà la comunità – Run2

+1

Appena aggiunto un po 'di codice sopra – Run2

+0

Questo è uguale alle altre risposte da exp (x)/(1 + exp (x)) = 1/(1 + exp (-x)), e il peso per albero 0 è 1 rispetto al tasso di apprendimento – Brian

1
def score(features: Vector,gbdt: GradientBoostedTreesModel): Double = { 
    val treePredictions = gbdt.trees.map(_.predict(features)) 
    blas.ddot(gbdt.numTrees, treePredictions, 1, gbdt.treeWeights, 1) 
} 
def sigmoid(v : Double) : Double = { 
    1/(1+Math.exp(-v)) 
} 
// model is output of GradientBoostedTrees.train(...,...) 
// testData is libSVM format 
val labelAndPreds = testData.map { point => 
     var prediction = score(point.features,model) 
     prediction = sigmoid(prediction) 
     (point.label, Vectors.dense(1.0-prediction, prediction)) 
} 
2

Ecco il mio approccio utilizzando le dipendenze interne di Spark. Sarà necessario importare la libreria algebra lineare per l'operazione matriciale in un secondo momento, ossia moltiplicare le previsioni dell'albero con il tasso di apprendimento.

import org.apache.spark.mllib.linalg.{Vectors, Matrices} 
import org.apache.spark.mllib.linalg.distributed.{RowMatrix} 

Di 'a costruire un modello con GBT:

val model = GradientBoostedTrees.train(trainingData, boostingStrategy) 

per calcolare la probabilità utilizzando il modello a oggetti:

// Get the log odds predictions from each tree 
val treePredictions = testData.map { point => model.trees.map(_.predict(point.features)) } 

// Transform the arrays into matrices for multiplication 
val treePredictionsVector = treePredictions.map(array => Vectors.dense(array)) 
val treePredictionsMatrix = new RowMatrix(treePredictionsVector) 
val learningRate = model.treeWeights 
val learningRateMatrix = Matrices.dense(learningRate.size, 1, learningRate) 
val weightedTreePredictions = treePredictionsMatrix.multiply(learningRateMatrix) 

// Calculate probability by ensembling the log odds 
val classProb = weightedTreePredictions.rows.flatMap(_.toArray).map(x => 1/(1 + Math.exp(-1 * x))) 
classProb.collect 

// You may tweak your decision boundary for different class labels 
val classLabel = classProb.map(x => if (x > 0.5) 1.0 else 0.0) 
classLabel.collect 

Ecco un frammento di codice è possibile copiare & incolla direttamente nella scatola di accensione:

import org.apache.spark.mllib.regression.LabeledPoint 
import org.apache.spark.mllib.linalg.{Vectors, Matrices} 
import org.apache.spark.mllib.linalg.distributed.{RowMatrix} 
import org.apache.spark.mllib.tree.GradientBoostedTrees 
import org.apache.spark.mllib.tree.configuration.BoostingStrategy 
import org.apache.spark.mllib.tree.model.GradientBoostedTreesModel 

// Load and parse the data file. 
val csvData = sc.textFile("data/mllib/sample_tree_data.csv") 
val data = csvData.map { line => 
    val parts = line.split(',').map(_.toDouble) 
    LabeledPoint(parts(0), Vectors.dense(parts.tail)) 
} 
// Split the data into training and test sets (30% held out for testing) 
val splits = data.randomSplit(Array(0.7, 0.3)) 
val (trainingData, testData) = (splits(0), splits(1)) 

// Train a GBT model. 
val boostingStrategy = BoostingStrategy.defaultParams("Classification") 
boostingStrategy.numIterations = 50 
boostingStrategy.treeStrategy.numClasses = 2 
boostingStrategy.treeStrategy.maxDepth = 6 
boostingStrategy.treeStrategy.categoricalFeaturesInfo = Map[Int, Int]() 

val model = GradientBoostedTrees.train(trainingData, boostingStrategy) 

// Get class label from raw predict function 
val predictedLabels = model.predict(testData.map(_.features)) 
predictedLabels.collect 

// Get class probability 
val treePredictions = testData.map { point => model.trees.map(_.predict(point.features)) } 
val treePredictionsVector = treePredictions.map(array => Vectors.dense(array)) 
val treePredictionsMatrix = new RowMatrix(treePredictionsVector) 
val learningRate = model.treeWeights 
val learningRateMatrix = Matrices.dense(learningRate.size, 1, learningRate) 
val weightedTreePredictions = treePredictionsMatrix.multiply(learningRateMatrix) 
val classProb = weightedTreePredictions.rows.flatMap(_.toArray).map(x => 1/(1 + Math.exp(-1 * x))) 
val classLabel = classProb.map(x => if (x > 0.5) 1.0 else 0.0) 
classLabel.collect 
0

In effetti, l'ans sopra è errato, la funzione sigmoid è falsa in questa situazione per l'etichetta di conversione della scintilla in {-1,1}. È necessario utilizzare un codice come questo:

def score(features: Vector,gbdt: GradientBoostedTreesModel): Double = { 
    val treePredictions = gbdt.trees.map(_.predict(features)) 
    blas.ddot(gbdt.numTrees, treePredictions, 1, gbdt.treeWeights, 1) 
} 
val labelAndPreds = testData.map { point => 
     var prediction = score(point.features,model) 
     prediction = 1.0/(1.0 + math.exp(-2.0 * prediction)) 
     (point.label, Vectors.dense(1.0-prediction, prediction)) 
} 

Il dettaglio più si può vedere nella pagina 9 di "Approssimazione Funzione Greedy un gradiente Aumentare macchina?". E una richiesta di pull in spark: https://github.com/apache/spark/pull/16441

Problemi correlati