Github user srowen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/6761#discussion_r32512311
  
    --- Diff: 
mllib/src/main/scala/org/apache/spark/mllib/classification/NaiveBayes.scala ---
    @@ -113,6 +106,55 @@ class NaiveBayesModel private[mllib] (
         }
       }
     
    +  def predictProbabilities(testData: RDD[Vector]): RDD[Map[Double, 
Double]] = {
    +    val bcModel = testData.context.broadcast(this)
    +    testData.mapPartitions { iter =>
    +      val model = bcModel.value
    +      iter.map(model.predictProbabilities)
    +    }
    +  }
    +
    +  def predictProbabilities(testData: Vector): Map[Double, Double] = {
    +    modelType match {
    +      case Multinomial =>
    +        val prob = multinomialCalculation(testData)
    +        posteriorProbabilities(prob)
    +      case Bernoulli =>
    +        val prob = bernoulliCalculation(testData)
    +        posteriorProbabilities(prob)
    +      case _ =>
    +        // This should never happen.
    +        throw new UnknownError(s"Invalid modelType: $modelType.")
    +    }
    +  }
    +
    +  protected[classification] def multinomialCalculation(testData: Vector): 
DenseVector = {
    +    val prob = thetaMatrix.multiply(testData)
    +    BLAS.axpy(1.0, piVector, prob)
    +    prob
    +  }
    +
    +  protected[classification] def bernoulliCalculation(testData: Vector): 
DenseVector = {
    +    testData.foreachActive { (index, value) =>
    +      if (value != 0.0 && value != 1.0) {
    +        throw new SparkException(
    +          s"Bernoulli naive Bayes requires 0 or 1 feature values but found 
$testData.")
    +      }
    +    }
    +    val prob = thetaMinusNegTheta.get.multiply(testData)
    +    BLAS.axpy(1.0, piVector, prob)
    +    BLAS.axpy(1.0, negThetaSum.get, prob)
    +    prob
    +  }
    +
    +  protected[classification] def posteriorProbabilities(prob: DenseVector): 
Map[Double, Double] = {
    +    val maxLogs = max(prob.toBreeze)
    +    val minLogs = min(prob.toBreeze)
    +    val normalized = prob.toArray.map(e => (e - minLogs) / (maxLogs - 
minLogs))
    --- End diff --
    
    No, that's not at all valid. These are _log probabilities_. Dividing by 
1000 completely changes the probabilities relative to one another. You can 
_add_ a constant to log probabilities to scale the probabilities by a constant 
factor.
    
    The best thing is probably to subtract out the largest log first
    
    ```
    val probArray = prob.toArray
    val maxLog = probArray.max
    val probabilities = probArray.map(lp => math.exp(lp - maxLog))
    val probSum = probabilities.sum
    labels.zip(probabilities.map(_ / probSum)).toMap
    ```


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at [email protected] or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to