You are viewing a plain text version of this content. The canonical link for it is here.
Posted to reviews@spark.apache.org by GitBox <gi...@apache.org> on 2022/12/07 15:40:04 UTC
[GitHub] [spark] srowen commented on a diff in pull request #38966: [SPARK-41008][MLLIB] Dedup isotonic regression duplicate features
srowen commented on code in PR #38966:
URL: https://github.com/apache/spark/pull/38966#discussion_r1042358866
##########
mllib/src/main/scala/org/apache/spark/mllib/regression/IsotonicRegression.scala:
##########
@@ -307,6 +307,99 @@ class IsotonicRegression private (private var isotonic: Boolean) extends Seriali
run(input.rdd.retag.asInstanceOf[RDD[(Double, Double, Double)]])
}
+ /**
+ * Aggregates points of duplicate feature values into a single point using as label the weighted
+ * average of the labels of the points with duplicate feature values. All points for a unique
+ * feature values are aggregated as:
+ *
+ * - Aggregated label is the weighted average of all labels
+ * - Aggregated feature is the weighted average of all equal features[1]
+ * - Aggregated weight is the sum of all weights
+ *
+ * [1] Note: It is possible that feature values to be equal up to a resolution due to
+ * representation errors, since we cannot know which feature value to use in that case, we
+ * compute the weighted average of the features. Ideally, all feature values will be equal and
+ * the weighted average is just the value at any point.
+ *
+ * @param input
+ * Input data of tuples (label, feature, weight). Weights must be non-negative.
+ * @return
+ * Points with unique feature values.
+ */
+ private[regression] def makeUnique(
+ input: Array[(Double, Double, Double)]): Array[(Double, Double, Double)] = {
+
+ val cleanInput = input.filter { case (y, x, weight) =>
+ require(
+ weight >= 0.0,
+ s"Negative weight at point ($y, $x, $weight). Weights must be non-negative")
+ weight > 0
+ }
+
+ if (cleanInput.isEmpty) Array.empty
Review Comment:
Expand the if-else so bodies are on new lines
##########
mllib/src/main/scala/org/apache/spark/mllib/regression/IsotonicRegression.scala:
##########
@@ -307,6 +307,99 @@ class IsotonicRegression private (private var isotonic: Boolean) extends Seriali
run(input.rdd.retag.asInstanceOf[RDD[(Double, Double, Double)]])
}
+ /**
+ * Aggregates points of duplicate feature values into a single point using as label the weighted
+ * average of the labels of the points with duplicate feature values. All points for a unique
+ * feature values are aggregated as:
+ *
+ * - Aggregated label is the weighted average of all labels
+ * - Aggregated feature is the weighted average of all equal features[1]
+ * - Aggregated weight is the sum of all weights
+ *
+ * [1] Note: It is possible that feature values to be equal up to a resolution due to
+ * representation errors, since we cannot know which feature value to use in that case, we
+ * compute the weighted average of the features. Ideally, all feature values will be equal and
+ * the weighted average is just the value at any point.
+ *
+ * @param input
+ * Input data of tuples (label, feature, weight). Weights must be non-negative.
+ * @return
+ * Points with unique feature values.
+ */
+ private[regression] def makeUnique(
+ input: Array[(Double, Double, Double)]): Array[(Double, Double, Double)] = {
+
+ val cleanInput = input.filter { case (y, x, weight) =>
+ require(
+ weight >= 0.0,
+ s"Negative weight at point ($y, $x, $weight). Weights must be non-negative")
+ weight > 0
+ }
+
+ if (cleanInput.isEmpty) Array.empty
+ else if (cleanInput.length <= 1) cleanInput
+ else {
+ // whether or not two double features are equal up to a precision
+ @inline def areEqual(a: Double, b: Double): Boolean = Precision.equals(a, b)
+
+ // Utility object, holds a buffer of all points with unique features so far, and performs
+ // weighted sum accumulation of points. Hides these details for better readability of the
+ // main algorithm.
+ object PointsAccumulator {
Review Comment:
Maybe make this a top-level object in this file at least, if not a separate file
##########
mllib/src/test/scala/org/apache/spark/mllib/regression/IsotonicRegressionSuite.scala:
##########
@@ -194,40 +241,46 @@ class IsotonicRegressionSuite extends SparkFunSuite with MLlibTestSparkContext w
assert(model.predict(0.5) === 1.5)
assert(model.predict(0.75) === 1.75)
assert(model.predict(1) === 2)
- assert(model.predict(2) === 10d/3)
- assert(model.predict(9) === 10d/3)
+ assert(model.predict(2) === 10d / 3)
Review Comment:
You're welcome to just write 10.0 / 3 here too
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org