Skip to content

[MRG+2] ENH&BUG Add pos_label parameter and fix a bug in average_precision_score #9980

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 16, 2018
Merged

[MRG+2] ENH&BUG Add pos_label parameter and fix a bug in average_precision_score #9980

merged 11 commits into from
Jul 16, 2018

Conversation

qinhanmin2014
Copy link
Member

@qinhanmin2014 qinhanmin2014 commented Oct 23, 2017

Reference Issues/PRs

part of #9829

What does this implement/fix? Explain your changes.

(1)add pos_label parameter to average_precision_score (Although we finally decide not to introduce pos_label in roc_auc_score, I think we might need pos_label here. Because there are no relationship between the results if we reverse the true labels, also, precision/recall all support pos_label)
(2)fix a bug where average_precision_score will sometimes return nan when sample_weight contains 0

y_true = np.array([0, 0, 0, 1, 1, 1])
y_score = np.array([0.1, 0.4, 0.85, 0.35, 0.8, 0.9])
average_precision_score(y_true, y_score, sample_weight=[1, 1, 0, 1, 1, 0])
# output:nan

I do it here because of (3)
(3)move average_precision scores out of METRIC_UNDEFINED_BINARY (this should contain the regression test for (1) and (2))

Some comments:
(1)For the underlying method(precision_recall_curve), the default value of pos_label is None, but I choose to set the default value of pos_label to 1 because this is what P/R/F is doing. What's more, the meaning of pos_label=None is not clear even in scikit-learn itself (see #10010)
(2)I slightly modified the common test. Currently, the part I modified is only designed for brier_score_loss(I'm doing the same thing in #9562) . I think it is right because as a common test, it seems not good to force metrics to accept str y_true without pos_label.

Any other comments?

cc @jnothman Could you please take some time to review or at least judge whether this is the right way to go? Thanks a lot :)

@qinhanmin2014
Copy link
Member Author

ping @jnothman Could you please take some time to review it or at least judge whether this is the right way to go? Thanks a lot :)

@jnothman
Copy link
Member

jnothman commented Oct 26, 2017 via email

@qinhanmin2014
Copy link
Member Author

ping @jnothman for a review. Thanks :)

Copy link
Member

@jnothman jnothman left a comment

Choose a reason for hiding this comment

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

Otherwise LGTM


y_type = type_of_target(y_true)
if y_type == "binary":
_partial_binary_uninterpolated_average_precision = partial(
Copy link
Member

Choose a reason for hiding this comment

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

This is used once. It can have a short, uninformative name...

@@ -173,6 +174,10 @@ def average_precision_score(y_true, y_score, average="macro",
``'samples'``:
Calculate metrics for each instance, and find their average.

pos_label : int or str (default=1)
The label of the positive class. For multilabel-indicator y_true,
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps clarify that this is only applied to binary classification. We do not, for instance, binarize a multiclass problem using pos_label...

return _average_binary_score(
_partial_binary_uninterpolated_average_precision, y_true,
y_score, average, sample_weight=sample_weight)
else:
Copy link
Member

Choose a reason for hiding this comment

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

are we sure at this stage that the y_type is not multiclass?

raise ValueError("Parameter pos_label is fixed to 1 for "
"multilabel-indicator y_true. Do not set "
"pos_label or set pos_label to 1.")
return _average_binary_score(
Copy link
Member

Choose a reason for hiding this comment

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

Why don't you outdent this and use it in all cases?

@qinhanmin2014
Copy link
Member Author

@jnothman Thanks a lot for the review :) Comments addressed. I also simplify the code.

are we sure at this stage that the y_type is not multiclass?

At this point not. But we do the check once we finish the preparation and enter _average_binary_score, so I think it seems unnecessary to add a duplicate check here.

Copy link
Member

@jnothman jnothman left a comment

Choose a reason for hiding this comment

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

LGTM. Please add what's new

@@ -150,7 +151,7 @@ def average_precision_score(y_true, y_score, average="macro",
Parameters
----------
y_true : array, shape = [n_samples] or [n_samples, n_classes]
True binary labels (either {0, 1} or {-1, 1}).
True binary labels or binary label indicators.
Copy link
Member

Choose a reason for hiding this comment

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

label indicators -> multilabel indicators ??

@jnothman jnothman changed the title [MRG] ENH&BUG Add pos_label parameter and fix a bug in average_precision_score [MRG+1] ENH&BUG Add pos_label parameter and fix a bug in average_precision_score Jan 16, 2018
@qinhanmin2014
Copy link
Member Author

@jnothman Thanks for the review :) I update what's new (not sure whether we need two entries)

label indicators -> multilabel indicators ??

I'm not creating term but just reverting the previous change (#9557) since we now extend the function. We are using the term binary label indicators in several places and we have stated that it's for multilabel case in the document. Do you think I need to change it? Thanks.

@jnothman
Copy link
Member

jnothman commented Jan 16, 2018 via email

Copy link
Member

@GaelVaroquaux GaelVaroquaux left a comment

Choose a reason for hiding this comment

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

This looks good aside from the cosmetic comment.

@@ -23,6 +23,7 @@
import numpy as np
from scipy.sparse import csr_matrix
from scipy.stats import rankdata
from functools import partial
Copy link
Member

Choose a reason for hiding this comment

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

Cosmetic: you should move this import to the top of the imports, as it is an import from the standard library.

@GaelVaroquaux
Copy link
Member

I am addressing the cosmetic comment myself and merging.

@GaelVaroquaux GaelVaroquaux changed the title [MRG+1] ENH&BUG Add pos_label parameter and fix a bug in average_precision_score [MRG+2] ENH&BUG Add pos_label parameter and fix a bug in average_precision_score Jul 16, 2018
Copy link
Member

@GaelVaroquaux GaelVaroquaux left a comment

Choose a reason for hiding this comment

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

LGTM.

Merging when CI is green.

@qinhanmin2014
Copy link
Member Author

Thanks a lot @GaelVaroquaux :)
FYI, I remove an unused variable.

@amueller amueller merged commit dd69361 into scikit-learn:master Jul 16, 2018
@qinhanmin2014 qinhanmin2014 deleted the average_precision_pos_label branch July 17, 2018 01:47
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