2016-05-18 2 views
5

Известно, что GBT s в Spark дает вам прогнозные метки на данный момент.Прогнозирование вероятностей классов в случае увеличения градиента деревьев в искровом свете с использованием выходного дерева

Я думал о попытке вычислить предсказанные вероятности для класса (скажем, все случаи, подпадающие под определенный лист)

Коды для построения ББТ-х

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 

Это дает мне 2 дерева глубины 2, как показано ниже для простоты:

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 

Мой вопрос: Могу ли я использовать выше деревьев, чтобы вычислить предсказанные вероятности, как:

В отношении каждого экземпляра в наборе функций, используемый для прогнозирования

ехра (лист балла из дерева 0 + лист балла из дерева 1)/(1 + ехр (лист балла из дерева счета 0 + листа из дерева-))

Это дает мне некоторую вероятность. Но не уверен, что это правильный способ сделать это. Также, если есть какой-либо документ, объясняющий, как рассчитывается оценка листа (прогноз). Я был бы очень благодарен, если кто-то может поделиться.

Любое предложение было бы превосходным.

ответ

0

На самом деле я смог предсказать вероятности с использованием дерева и формулировки дерева, заданного в вопросе. Я на самом деле проверил с прогнозируемым лейблом GBT. Он соответствует точно, когда я использую порог как 0,5.

Таким образом, мы делаем то же самое с небольшими изменениями.

В отношении каждого экземпляра в наборе функций, используемый для прогнозирования:

ехра (лист оценка от дерева 0 + (learning_rate) * лист оценка от дерева 1)/(1 + ехр (лист балла из дерева- + (learning_rate) * оценка листа с дерева 1))

Это по существу дает мне предсказанные вероятности.

Я тестировал то же самое на 3 деревьях с глубиной 3. Это сработало. А также с различными наборами данных.

Было бы здорово узнать, если кто-то еще это пробовал. Если нет, они могут попробовать это и прокомментировать.

+1

Почему бы вам не вставить код вычисления вероятности здесь. Это поможет сообществу – Run2

+1

Просто добавленный код выше – Run2

+0

Это то же самое, что и другие ответы, так как exp (x)/(1 + exp (x)) = 1/(1 + exp (-x)), а вес для дерева 0 равен 1 в отличие от скорости обучения – 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

Вот мой подход с использованием внутренних зависимостей Spark. Вам нужно будет импортировать библиотеку линейной алгебры для операции с матрицей позже, т. Е. Умножить предсказания дерева на скорость обучения.

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

Допустим, вы построить модель с ББТ:

val model = GradientBoostedTrees.train(trainingData, boostingStrategy) 

Для вычисления вероятности с использованием модели объекта:

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

Вот фрагмент кода, вы можете скопировать & паста непосредственно в искровую оболочку:

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

Фактически, вышеупомянутые анс ошибочны, сигмоидальная функция в этой ситуации ложна, чтобы исправить переводную метку в {-1,1}. Вы должны использовать такой код:

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

Более подробно можно увидеть на странице 9 «жадного аппроксимирующей функции градиентной Повышая машина?». И запрос на изгиб в искры: https://github.com/apache/spark/pull/16441

Смежные вопросы