com.alpine.result.ScoringResult.scala Maven / Gradle / Ivy
/*
* Copyright (c) 2015 Alpine Data Labs
* All rights reserved.
*/
package com.alpine.result
trait MLResult {
def value: Any
/**
* Used in tests to compare results, within a given numerical tolerance range.
*/
def equals(other: MLResult, tolerance: Double): Boolean
}
trait CategoricalResult extends MLResult {
/**
* @return The simple value of the prediction. e.g. "yes" or "1".
*/
def value: String
/**
* @return The index by which the prediction value may be found in the list of labels.
*/
def index: Int = labels.indexOf(value)
/**
* @return The list of potential labels that can be generated by the model. e.g. ["yes", "no"]
*/
def labels: Seq[String]
/**
* A numeric detail generated by the model for each label. Typically, this is a value which is minimized or maximized
* to determine the predicted value.
* e.g. confidence probabilities (to be maximised)
* or distance to the labelled cluster (to be minimised).
*
* This MUST be in the same order as the list returned by "labels".
* @return A list of numeric details corresponding to the labels (order must be preserved).
*/
def details: Array[Double]
override def equals(other: MLResult, tolerance: Double): Boolean = {
other match {
case result: CategoricalResult =>
if (result.labels == this.labels && result.details.length == details.length) {
var i = 0
var sum = 0d
while (i < details.length) {
sum += math.abs(details(i) - result.details(i))
i += 1
}
sum <= tolerance
} else {
false
}
case _ => false
}
}
override def equals(obj: scala.Any): Boolean = {
obj.isInstanceOf[MLResult] && this.equals(obj.asInstanceOf[MLResult], 0)
}
}
case class RealResult(value: Double) extends MLResult {
override def equals(other: MLResult, tol: Double): Boolean = {
other match {
case result: RealResult =>
math.abs(value - result.value) <= tol // Do <= in case tol is 0.
case _ => false
}
}
}
/**
* The value is the arg min of the distances.
*/
case class ClusteringResult(labels: Seq[String], distances: Array[Double])
extends CategoricalResult {
override lazy val (value, index) = {
var i = 0
var minDistance = Double.MaxValue
var minIndex = -1
while (i < labels.length) {
if (distances(i) < minDistance) {
minDistance = distances(i)
minIndex = i
}
i += 1
}
if (minIndex < 0) ("", minIndex) else (labels(minIndex), minIndex)
}
override def details: Array[Double] = distances
override def equals(other: MLResult, tolerance: Double): Boolean = {
other.isInstanceOf[ClusteringResult] && super.equals(other, tolerance)
}
}
/**
* The value is the arg max of the confidences.
*/
case class ClassificationResult(labels: Seq[String], confidences: Array[Double])
extends CategoricalResult {
override lazy val (value, index) = {
var i = 0
var maxConfidence = Double.MinValue
var maxIndex = -1
while (i < labels.length) {
if (confidences(i) > maxConfidence) {
maxConfidence = confidences(i)
maxIndex = i
}
i += 1
}
if (maxIndex < 0) ("", maxIndex) else (labels(maxIndex), maxIndex)
}
override def details: Array[Double] = confidences
override def equals(other: MLResult, tolerance: Double = 0): Boolean = {
other.isInstanceOf[ClassificationResult] && super.equals(other, tolerance)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy