FIX accept multilabel-indicator in _get_response_values - #27002
Conversation
…to make_scorer_list_response
|
pinging @adrinjalali @thomasjpfan @betatim I think this is ready for a review with a much shorter diff only for the initial bug. |
Co-authored-by: Thomas J. Fan <[email protected]>
| if pos_label == classes[0]: | ||
| y_pred *= -1 | ||
| elif target_type == "multilabel-indicator" and isinstance(y_pred, list): | ||
| y_pred = np.vstack([p for p in y_pred]).T |
There was a problem hiding this comment.
In this case, this is the same story. However, I don't recall any estimator that would return a list currently.
adrinjalali
left a comment
There was a problem hiding this comment.
I feel like there are things in your head which are not expressed here, and they would help me review this PR better 😁
| @@ -72,15 +73,15 @@ def _get_response_values( | |||
| if is_classifier(estimator): | |||
There was a problem hiding this comment.
do you think this whole block could be simplified / explained? I have a hard time following all these different code paths, and trying to figure out if they actually cover all possible input types, and realized this is kind of a symptom of how this is written.
There was a problem hiding this comment.
I am not sure where to put the cursor here. Mainly, the issue is that we need a compressed format (n_samples,) or (n_samples, n_outputs) (i.e. at least our metrics need to). So we leverage pos_label to provide the correct array.
There was a problem hiding this comment.
I created new function and try to better explain what we intend to do.
There was a problem hiding this comment.
LOVE the new implementation.
jeremiedbb
left a comment
There was a problem hiding this comment.
I like the refactoring into smaller dedicated functions and their description. It makes the code a lot easier to follow imo. I just have a few nitpicks, otherwise LGTM.
Co-authored-by: Jérémie du Boisberranger <[email protected]>
…kit-learn#26568) Co-authored-by: Guillaume Lemaitre <[email protected]> Co-authored-by: Jérémie du Boisberranger <[email protected]>
Co-authored-by: jeremie du boisberranger <[email protected]>
Co-authored-by: Tim Head <[email protected]>
…kit-learn#26521) Co-authored-by: Jérémie du Boisberranger <[email protected]> Co-authored-by: Olivier Grisel <[email protected]>
…s_neighbors_graph (scikit-learn#27245) Co-authored-by: Jérémie du Boisberranger <[email protected]>
adrinjalali
left a comment
There was a problem hiding this comment.
this is a really nice refactor now. LGTM other than the small points.
| y_pred : ndarray of shape (n_samples,), (n_samples, n_classes) or \ | ||
| (n_samples, n_output) | ||
| Compressed predictions format as requested by the metrics. |
There was a problem hiding this comment.
kinda wondering why this is not our output in the fist place 😁
There was a problem hiding this comment.
Basically, I think this is dependent on the estimator and does it naturally or not output values.
| if target_type == "binary" and y_pred.shape[1] < 2: | ||
| # We don't handle classifiers trained on a single class. | ||
| raise ValueError( | ||
| f"Got predict_proba of shape {y_pred.shape}, but need " | ||
| "classifier with two classes." | ||
| ) |
There was a problem hiding this comment.
I can imagine this happening in cases where we do cross validation or grid search, I feel like we shouldn't be raising.
There was a problem hiding this comment.
I recall that this code was actually here in previous iteration before the refactoring. Looking a bit more, I don't think that all estimators support this one in scikit-learn (e.g. LogisticRegression does not for instance).
In terms of predict_proba, I could potentially make a PR that handle this case: we need to returns the probability in regards of pos_label to be consistent with estimator.classes_.
In short, we should have: y_pred.ravel() if pos_label == estimator.classes_[0] else np.abs(1 - y_pred.ravel()).
| In the binary case, it should invert the sign of the score if the positive label | ||
| is not `classes[1]`. In the multi-label case, it should stack the predictions if |
There was a problem hiding this comment.
this inversion of the sign is making me very uncomfortable, will need some time to see if it makes things explode in other places. Can you help me here?
There was a problem hiding this comment.
Actually, the sign inversion and selection selection of the columns is indeed part of bug fixes that we got since a couple of release now :).
You you change your pos_label then you flip the hyperplane. In terms of binary probability, it comes to take the other columns and therefore the 1 - y_proba. Both, are consistent.
| # returns an array of shape `(n_samples, n_outputs)`. | ||
| # We could remove this code in the future? |
There was a problem hiding this comment.
that means this code is never run? then why do we have it?
There was a problem hiding this comment.
Because we wrote some tests for it and thus silently supporting it.
We would not have tests, I would have been inclined removing it.
Here, we could potentially break code. It might not be worth it.
There was a problem hiding this comment.
Then I would simply remove it. It's not a documented behavior anyway.
| @@ -72,15 +73,15 @@ def _get_response_values( | |||
| if is_classifier(estimator): | |||
There was a problem hiding this comment.
LOVE the new implementation.
…#27002) Co-authored-by: Thomas J. Fan <[email protected]> Co-authored-by: Jérémie du Boisberranger <[email protected]> Co-authored-by: Stefanie Senger <[email protected]> Co-authored-by: Vladimir Fokow <[email protected]> Co-authored-by: jeremie du boisberranger <[email protected]> Co-authored-by: Xuefeng Xu <[email protected]> Co-authored-by: Tim Head <[email protected]> Co-authored-by: Raphael <[email protected]> Co-authored-by: Olivier Grisel <[email protected]> Co-authored-by: Sayed Qaiser Ali <[email protected]> Co-authored-by: Loïc Estève <[email protected]> Co-authored-by: Xiao Yuan <[email protected]>
…#27002) Co-authored-by: Thomas J. Fan <[email protected]> Co-authored-by: Jérémie du Boisberranger <[email protected]> Co-authored-by: Stefanie Senger <[email protected]> Co-authored-by: Vladimir Fokow <[email protected]> Co-authored-by: jeremie du boisberranger <[email protected]> Co-authored-by: Xuefeng Xu <[email protected]> Co-authored-by: Tim Head <[email protected]> Co-authored-by: Raphael <[email protected]> Co-authored-by: Olivier Grisel <[email protected]> Co-authored-by: Sayed Qaiser Ali <[email protected]> Co-authored-by: Loïc Estève <[email protected]> Co-authored-by: Xiao Yuan <[email protected]>
Co-authored-by: Thomas J. Fan <[email protected]> Co-authored-by: Jérémie du Boisberranger <[email protected]> Co-authored-by: Stefanie Senger <[email protected]> Co-authored-by: Vladimir Fokow <[email protected]> Co-authored-by: jeremie du boisberranger <[email protected]> Co-authored-by: Xuefeng Xu <[email protected]> Co-authored-by: Tim Head <[email protected]> Co-authored-by: Raphael <[email protected]> Co-authored-by: Olivier Grisel <[email protected]> Co-authored-by: Sayed Qaiser Ali <[email protected]> Co-authored-by: Loïc Estève <[email protected]> Co-authored-by: Xiao Yuan <[email protected]>
…#27002) Co-authored-by: Thomas J. Fan <[email protected]> Co-authored-by: Jérémie du Boisberranger <[email protected]> Co-authored-by: Stefanie Senger <[email protected]> Co-authored-by: Vladimir Fokow <[email protected]> Co-authored-by: jeremie du boisberranger <[email protected]> Co-authored-by: Xuefeng Xu <[email protected]> Co-authored-by: Tim Head <[email protected]> Co-authored-by: Raphael <[email protected]> Co-authored-by: Olivier Grisel <[email protected]> Co-authored-by: Sayed Qaiser Ali <[email protected]> Co-authored-by: Loïc Estève <[email protected]> Co-authored-by: Xiao Yuan <[email protected]>
closes #26817
Accept "multilabel-indicator" in
_get_response_values.