Skip to content

Conversation

@imatiach-msft
Copy link
Contributor

@imatiach-msft imatiach-msft commented Feb 27, 2017

What changes were proposed in this pull request?

The evaluators BinaryClassificationEvaluator, RegressionEvaluator, and MulticlassClassificationEvaluator and the corresponding metrics classes BinaryClassificationMetrics, RegressionMetrics and MulticlassMetrics should use sample weight data.

I've closed the PR: #16557
as recommended in favor of creating three pull requests, one for each of the evaluators (binary/regression/multiclass) to make it easier to review/update.

Note: I've updated the JIRA to:
https://issues.apache.org/jira/browse/SPARK-24101
Which is a child of JIRA:
https://issues.apache.org/jira/browse/SPARK-18693

How was this patch tested?

I added tests to the metrics class.

@SparkQA
Copy link

SparkQA commented Feb 27, 2017

Test build #73529 has finished for PR 17086 at commit cf6a5ab.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
  • class MulticlassMetrics @Since(\"1.1.0\") (predAndLabelsWithOptWeight: RDD[_])

@imatiach-msft
Copy link
Contributor Author

@sethah @Lewuathe @thunterdb @WeichenXu123 @jkbradley @actuaryzhang @srowen would you be able to take a look? I've split the larger pull request into three parts as suggested.

@imatiach-msft
Copy link
Contributor Author

ping @sethah @Lewuathe @thunterdb @WeichenXu123 @jkbradley @actuaryzhang @srowen could you please take a look? thank you!

@SparkQA
Copy link

SparkQA commented Jun 21, 2017

Test build #78372 has started for PR 17086 at commit cf6a5ab.

@imatiach-msft imatiach-msft force-pushed the ilmat/multiclass-evaluate branch from cf6a5ab to 4a0debf Compare April 16, 2018 16:54
@imatiach-msft
Copy link
Contributor Author

jenkins, retest this please

@SparkQA
Copy link

SparkQA commented Apr 16, 2018

Test build #89407 has finished for PR 17086 at commit 4a0debf.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
  • class MulticlassMetrics @Since(\"1.1.0\") (predAndLabelsWithOptWeight: RDD[_])

Copy link
Contributor

@WeichenXu123 WeichenXu123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I made an initial rough review.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Since("2.4.0")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line seems useless ? dataset.select(pred, label)...values.countByValues()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch -- hmm that shouldn't be there, not sure why I added it, removed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to define two constructor as:

this(predAndLabelsWithOptWeight: RDD[(Double, Double, Double)]
this(predAndLabels: RDD[(Double, Double)])

so it will do more strict type checking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea, this also simplifies the calculation of the confusions, fpByClass, tpByClass and labelCountByClass

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm the build fails here though with an error indicating that the methods are the same after type erasure, perhaps I should revert this code back:

[error] /home/jenkins/workspace/SparkPullRequestBuilder@2/mllib/src/main/scala/org/apache/spark/mllib/evaluation/MulticlassMetrics.scala:35: double definition:
[error] constructor MulticlassMetrics: (predLabelsWeight: org.apache.spark.rdd.RDD[(Double, Double, Double)])org.apache.spark.mllib.evaluation.MulticlassMetrics at line 33 and
[error] constructor MulticlassMetrics: (predAndLabels: org.apache.spark.rdd.RDD[(Double, Double)])org.apache.spark.mllib.evaluation.MulticlassMetrics at line 35
[error] have same type after erasure: (predLabelsWeight: org.apache.spark.rdd.RDD)org.apache.spark.mllib.evaluation.MulticlassMetrics
[error] def this(predAndLabels: RDD[(Double, Double)]) =

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add a member var into the class like val predAndLabelsWithOptWeight: RDD[(Double, Double, Double), and ctor assign this member var. so the following calculation code will be easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea, done!

@SparkQA
Copy link

SparkQA commented Apr 18, 2018

Test build #89483 has finished for PR 17086 at commit cf941af.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
  • class MulticlassMetrics @Since(\"2.4.0\") (predLabelsWeight: RDD[(Double, Double, Double)])

@SparkQA
Copy link

SparkQA commented Apr 19, 2018

Test build #89551 has finished for PR 17086 at commit 4a5be4a.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
  • class MulticlassMetrics @Since(\"2.4.0\") (predAndLabelsWithOptWeight: RDD[_])

@imatiach-msft
Copy link
Contributor Author

@WeichenXu123 I've updated the PR, resolved all comments and the build passes - would you be able to take another look when you have time? Thank you!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .mapValues(weight => weight) is redundant, it generate the same RDD.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch! removed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use 1E-7 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use operator A ~== B absTol delta like other tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There're many repeated expressions here such as (2 * w1 + 1 * w2 + 1 * w1) / tw, could you store them in variables first ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, I was trying to follow the format of the other existing test, made the change in both test cases

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use assert(metrics.labels === labels) like other tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't toArray, use assert(metrics.confusionMatrix ~== confusionMatrix relTol e)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like I needed to change this to an ML matrix instead of MLLIB matrix in order to make this ~== work, so I used .asML

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that's because you use Matrices in mllib, change it to Matrices in ml, i.e., import org.apache.spark.ml.linalg.Matrices

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

however, I still need to do asML on the metrics.confusionMatrix as that property is from mllib (in MulticlassMetrics class)

@imatiach-msft imatiach-msft force-pushed the ilmat/multiclass-evaluate branch from 112bba9 to 47c45cb Compare April 26, 2018 15:26
@SparkQA
Copy link

SparkQA commented Apr 26, 2018

Test build #89890 has finished for PR 17086 at commit 47c45cb.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds no public classes.

@imatiach-msft imatiach-msft force-pushed the ilmat/multiclass-evaluate branch from 47c45cb to 089d64b Compare April 26, 2018 15:41
@SparkQA
Copy link

SparkQA commented Apr 26, 2018

Test build #89891 has finished for PR 17086 at commit 089d64b.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds no public classes.

@imatiach-msft imatiach-msft changed the title [SPARK-18693][ML][MLLIB] ML Evaluators should use weight column - added weight column for multiclass classification evaluator [SPARK-24101][ML][MLLIB] ML Evaluators should use weight column - added weight column for multiclass classification evaluator Apr 26, 2018
@imatiach-msft imatiach-msft force-pushed the ilmat/multiclass-evaluate branch from 089d64b to 6906dc4 Compare April 26, 2018 16:32
@SparkQA
Copy link

SparkQA commented Apr 26, 2018

Test build #89894 has finished for PR 17086 at commit 6906dc4.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe relTol will be better than absTol, except the cases that one side is zero. What do you think of it ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea, I've replaced absTol with relTol, done

@WeichenXu123
Copy link
Contributor

overall good, @jkbradley Would you mind take a look ?

@imatiach-msft imatiach-msft force-pushed the ilmat/multiclass-evaluate branch from 6906dc4 to f209bb4 Compare May 1, 2018 04:05
@imatiach-msft
Copy link
Contributor Author

jenkins, retest this please

1 similar comment
@imatiach-msft
Copy link
Contributor Author

jenkins, retest this please

@SparkQA
Copy link

SparkQA commented May 1, 2018

Test build #90000 has finished for PR 17086 at commit 7fc14c0.

  • This patch fails SparkR unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@imatiach-msft
Copy link
Contributor Author

looks like a random failure in spark R, unrelated

@imatiach-msft
Copy link
Contributor Author

jenkins, retest this please

@SparkQA
Copy link

SparkQA commented May 1, 2018

Test build #90002 has finished for PR 17086 at commit 7fc14c0.

  • This patch fails SparkR unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

Copy link
Member

@srowen srowen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am also pretty OK with this one; straightforward

@imatiach-msft imatiach-msft force-pushed the ilmat/multiclass-evaluate branch from a416fa0 to 0ca102a Compare November 6, 2018 03:52
@SparkQA
Copy link

SparkQA commented Nov 6, 2018

Test build #98503 has finished for PR 17086 at commit 0ca102a.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
  • class MulticlassMetrics @Since(\"3.0.0\") (predAndLabelsWithOptWeight: RDD[_])

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, wait a sec, this changed the signature. I think you have to retain both. The RDD[(Double, Double)] constructor should stay, one way or the other, and add a new RDD[(Double, Double, Double)] constructor, with appropriate Since tags on each.

Below there's a DataFrame constructor and I'm not sure how to handle that. It should also handle the case where there's a weight col, but I'm not sure how to do that cleanly. There can be a second argument like hasWeightCol but that's starting to feel hacky.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@srowen hmm, this was already suggested, please see this comment: #17086 (comment)
the build fails with an error due to Java type erasure, so this wouldn't work... you can't have two constructors with the same type erased signature... maybe I am misunderstanding something, and you meant something else? Are you sure this changes the signature in a way that breaks others, it should still allow RDD with a tuple of 2 Double values.
The error I get is:
[error] /home/jenkins/workspace/SparkPullRequestBuilder@2/mllib/src/main/scala/org/apache/spark/mllib/evaluation/MulticlassMetrics.scala:35: double definition:
[error] constructor MulticlassMetrics: (predLabelsWeight: org.apache.spark.rdd.RDD[(Double, Double, Double)])org.apache.spark.mllib.evaluation.MulticlassMetrics at line 33 and
[error] constructor MulticlassMetrics: (predAndLabels: org.apache.spark.rdd.RDD[(Double, Double)])org.apache.spark.mllib.evaluation.MulticlassMetrics at line 35
[error] have same type after erasure: (predLabelsWeight: org.apache.spark.rdd.RDD)org.apache.spark.mllib.evaluation.MulticlassMetrics
[error] def this(predAndLabels: RDD[(Double, Double)]) =

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Darn, OK. Hm, so this doesn't actually cause a source or binary change? OK, that could be fine. I guess MiMa didn't complain. I guess you can now do weird things like pass RDD[String] here and it'll fail quickly. I'm a little uneasy about it but it's probably acceptable. Any other opinions?

I am not sure what to do about the DataFrame issue though. I suspect most people will want to call with a DataFrame now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"I am not sure what to do about the DataFrame issue though", ah, I think I see your concern.
But, isn't this dataframe constructor private anyway, so it can't be used by anyone outside mllib:

private[mllib] def this(predictionAndLabels: DataFrame) =
this(predictionAndLabels.rdd.map(r => (r.getDouble(0), r.getDouble(1))))

I only modified the RDD part because that is what is used by the ML evaluator and it is what users outside spark can access. This is to add weight column for the evaluators.

However, even if we wanted to add weight column support for the private API, I'm unsure about how to add this. Should I just check if there are 3 columns or two, and if there are 3 use the third one as the weight column? I guess I am on the fence about this, I could change it but I don't think it is absolutely necessary, since it's not used anywhere outside spark MLLIB anyway.

Actually, this constructor is a bit weird, it looks like it was added as part of this PR:
https://github.com/apache/spark/pull/6011/files
It is only used here in the python API:
https://github.com/apache/spark/pull/6011/files#diff-443f766289f8090078531c3e1a1d6027R186
But I don't see why we couldn't just get the rdd there and remove the private constructor altogether (?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The python API takes an RDD, creates a DF, and then calls this private constructor with the DF, but I would think we could just pass the RDD directly

@SparkQA
Copy link

SparkQA commented Nov 6, 2018

Test build #98529 has finished for PR 17086 at commit 3f0aac6.

  • This patch fails Spark unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented Nov 6, 2018

Test build #98533 has finished for PR 17086 at commit 49a879e.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@imatiach-msft
Copy link
Contributor Author

@srowen would you be able to take another look at this PR? Also tagging @WeichenXu123 . Thank you!

@SparkQA
Copy link

SparkQA commented Nov 8, 2018

Test build #98575 has finished for PR 17086 at commit 88b4bad.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
  • class MulticlassMetrics @Since(\"1.1.0\") (predAndLabelsWithOptWeight: RDD[_ <: Product])

Copy link
Member

@srowen srowen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a merge conflict now, but that's looking good to me. I'd still like another reviewer, but am personally pretty comfortable with the change.

@imatiach-msft imatiach-msft force-pushed the ilmat/multiclass-evaluate branch from 88b4bad to d54cc55 Compare November 8, 2018 18:58
@SparkQA
Copy link

SparkQA commented Nov 8, 2018

Test build #98618 has finished for PR 17086 at commit d54cc55.

  • This patch fails to build.
  • This patch merges cleanly.
  • This patch adds the following public classes (experimental):
  • class MulticlassMetrics @Since(\"1.1.0\") (predAndLabelsWithOptWeight: RDD[_ <: Product])

@SparkQA
Copy link

SparkQA commented Nov 8, 2018

Test build #98619 has finished for PR 17086 at commit 5086449.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@imatiach-msft
Copy link
Contributor Author

@srowen thanks, I've fixed the merge conflict and updated to latest

@srowen
Copy link
Member

srowen commented Nov 9, 2018

Merged to master

@asfgit asfgit closed this in 8e5f3c6 Nov 9, 2018
@imatiach-msft
Copy link
Contributor Author

thank you @srowen ! I will try to update the other two PRs as soon as possible. Really exciting to see this get in.

jackylee-ch pushed a commit to jackylee-ch/spark that referenced this pull request Feb 18, 2019
…ed weight column for multiclass classification evaluator

## What changes were proposed in this pull request?

The evaluators BinaryClassificationEvaluator, RegressionEvaluator, and MulticlassClassificationEvaluator and the corresponding metrics classes BinaryClassificationMetrics, RegressionMetrics and MulticlassMetrics should use sample weight data.

I've closed the PR: apache#16557
 as recommended in favor of creating three pull requests, one for each of the evaluators (binary/regression/multiclass) to make it easier to review/update.

Note: I've updated the JIRA to:
https://issues.apache.org/jira/browse/SPARK-24101
Which is a child of JIRA:
https://issues.apache.org/jira/browse/SPARK-18693

## How was this patch tested?

I added tests to the metrics class.

Closes apache#17086 from imatiach-msft/ilmat/multiclass-evaluate.

Authored-by: Ilya Matiach <[email protected]>
Signed-off-by: Sean Owen <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants