预测Apache Spark MLib中Logistic回归模型的概率

时间:2015-05-22 08:02:31

标签: scala apache-spark

我正在使用Apache Spark来使用MLib提供的LogisticRegressionWithLBFGS()类来构建LRM。构建模型后,我们可以使用提供的预测函数,它只给出二进制标签作为输出。我也希望计算相同的概率。

中有相同的实现

https://github.com/apache/spark/blob/master/mllib/src/main/scala/org/apache/spark/mllib/classification/LogisticRegression.scala

override protected def predictPoint(
  dataMatrix: Vector,
  weightMatrix: Vector,
  intercept: Double) = {
require(dataMatrix.size == numFeatures)

// If dataMatrix and weightMatrix have the same dimension, it's binary logistic regression.
if (numClasses == 2) {
  val margin = dot(weightMatrix, dataMatrix) + intercept
  val score = 1.0 / (1.0 + math.exp(-margin))
  threshold match {
    case Some(t) => if (score > t) 1.0 else 0.0
    case None => score
  }
} 

此方法未公开,并且概率不可用。我可以知道如何使用此函数来获取概率。 上述函数中使用的点方法也没有公开,它存在于BLAS包中但不公开。

3 个答案:

答案 0 :(得分:5)

调用myModel.clearThreshold获取原始预测而不是0/1标签。

请注意,这仅适用于二元Logistic回归(numClasses == 2)。

答案 1 :(得分:3)

我在尝试获取多重问题的原始预测时遇到了类似的问题。对我来说,最好的解决方案是通过从Spark MLlib Logistic Regression src借用和定制来创建方法。您可以这样创建:

object ClassificationUtility {
  def predictPoint(dataMatrix: Vector, model: LogisticRegressionModel):
    (Double, Array[Double]) = {
    require(dataMatrix.size == model.numFeatures)
    val dataWithBiasSize: Int = model.weights.size / (model.numClasses - 1)
    val weightsArray: Array[Double] = model.weights match {
      case dv: DenseVector => dv.values
      case _ =>
        throw new IllegalArgumentException(
          s"weights only supports dense vector but got type ${model.weights.getClass}.")
    }
    var bestClass = 0
    var maxMargin = 0.0
    val withBias = dataMatrix.size + 1 == dataWithBiasSize
    val classProbabilities: Array[Double] = new Array[Double](model.numClasses)
    (0 until model.numClasses - 1).foreach { i =>
      var margin = 0.0
      dataMatrix.foreachActive { (index, value) =>
      if (value != 0.0) margin += value * weightsArray((i * dataWithBiasSize) + index)
      }
      // Intercept is required to be added into margin.
      if (withBias) {
        margin += weightsArray((i * dataWithBiasSize) + dataMatrix.size)
      }
      if (margin > maxMargin) {
        maxMargin = margin
        bestClass = i + 1
      }
      classProbabilities(i+1) = 1.0 / (1.0 + Math.exp(-(margin - maxMargin)))
    }
    return (bestClass.toDouble, classProbabilities)
  }
}

请注意,它与原始方法略有不同,它只是根据输入要素计算逻辑。它还定义了一些最初是私有的val和vars,并包含在此方法之外。最终,它会对数组中的分数进行索引,并将其与最佳答案一起返回。我这样称呼我的方法:

// Compute raw scores on the test set.
val predictionAndLabelsAndProbabilities = test
  .map { case LabeledPoint(label, features) =>
val (prediction, probabilities) = ClassificationUtility
  .predictPoint(features, model)
(prediction, label, probabilities)}

<强>然而

似乎Spark贡献者不鼓励使用MLlib支持ML。 ML逻辑回归API目前不支持多重分类。我现在使用OneVsRest作为一个与所有分类的包装器。我正在进行类似的定制以获得原始分数。

答案 2 :(得分:0)

我相信电话是myModel.clearThreshold();即没有括号的myModel.clearThreshold失败。请参阅线性SVM示例here