Skip to content

[MRG+2] Add max_error to the existing set of metrics for regression #12232

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 23 commits into from
Oct 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e40258f
Add max error metric
whiletruelearn Oct 1, 2018
6905ee4
Fix typo
whiletruelearn Oct 1, 2018
0e92ee3
Fix some imports
whiletruelearn Oct 1, 2018
06f14d8
Adding some test for max error
whiletruelearn Oct 1, 2018
ea9d3f0
Add scorer for max error
whiletruelearn Oct 1, 2018
7b8222f
Add max_error_scorer to fix the failing test
whiletruelearn Oct 3, 2018
237759a
correct typo in scorer name
whiletruelearn Oct 3, 2018
9f0f6de
Changes based on review comments
whiletruelearn Oct 4, 2018
495d6f0
Sample weight initialization needs to be tweaked to make the test pass
whiletruelearn Oct 4, 2018
0ab3513
Update sample weight only for the max_error scorer
whiletruelearn Oct 4, 2018
bb56761
Change the sample weight slightly
whiletruelearn Oct 4, 2018
7cfdb71
Remove support for sample weight
whiletruelearn Oct 4, 2018
ae86ca4
Changes based on code review
whiletruelearn Oct 4, 2018
d85f997
Fix the doctest
whiletruelearn Oct 4, 2018
361675a
update what's new
whiletruelearn Oct 7, 2018
5b82f09
Update the PR number also
whiletruelearn Oct 7, 2018
e296cdd
Update the user guide
whiletruelearn Oct 8, 2018
ff35504
update the documentation based on review comments
whiletruelearn Oct 8, 2018
cb50f23
Add reference and style fix for doc to have 80 char limit
whiletruelearn Oct 8, 2018
f156d59
Update review comments
whiletruelearn Oct 10, 2018
3e0dfcf
Doc updates
whiletruelearn Oct 11, 2018
a088a76
Better structuring of sentence
whiletruelearn Oct 11, 2018
90d69db
Missed to add the word metric
whiletruelearn Oct 11, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/modules/classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,7 @@ details.
:template: function.rst

metrics.explained_variance_score
metrics.max_error
metrics.mean_absolute_error
metrics.mean_squared_error
metrics.mean_squared_log_error
Expand Down
33 changes: 33 additions & 0 deletions doc/modules/model_evaluation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ Scoring Function

**Regression**
'explained_variance' :func:`metrics.explained_variance_score`
'max_error' :func:`metrics.max_error`
'neg_mean_absolute_error' :func:`metrics.mean_absolute_error`
'neg_mean_squared_error' :func:`metrics.mean_squared_error`
'neg_mean_squared_log_error' :func:`metrics.mean_squared_log_error`
Expand Down Expand Up @@ -1530,6 +1531,38 @@ function::
... # doctest: +ELLIPSIS
0.990...

.. _max_error:

Max error
-------------------

The :func:`max_error` function computes the maximum `residual error
<https://en.wikipedia.org/wiki/Errors_and_residuals>`_ , a metric
that captures the worst case error between the predicted value and
the true value. In a perfectly fitted single output regression
model, ``max_error`` would be ``0`` on the training set and though this
would be highly unlikely in the real world, this metric shows the
extent of error that the model had when it was fitted.


If :math:`\hat{y}_i` is the predicted value of the :math:`i`-th sample,
and :math:`y_i` is the corresponding true value, then the max error is
defined as

.. math::

\text{Max Error}(y, \hat{y}) = max(| y_i - \hat{y}_i |)

Here is a small example of usage of the :func:`max_error` function::

>>> from sklearn.metrics import max_error
>>> y_true = [3, 2, 7, 1]
>>> y_pred = [9, 2, 7, 1]
>>> max_error(y_true, y_pred)
6

The :func:`max_error` does not support multioutput.

.. _mean_absolute_error:

Mean absolute error
Expand Down
9 changes: 9 additions & 0 deletions doc/whats_new/v0.21.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ Support for Python 3.4 and below has been officially dropped.
graph, which would add explicitly zeros on the diagonal even when already
present. :issue:`12105` by `Tom Dupre la Tour`_.


:mod:`sklearn.metrics`
......................

- |Feature| Added the :func:`metrics.max_error` metric and a corresponding
``'max_error'`` scorer for single output regression.
:issue:`12232` by :user:`Krishna Sangeeth <whiletruelearn>`.


Multiple modules
................

Expand Down
3 changes: 3 additions & 0 deletions sklearn/metrics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,14 @@
from .pairwise import pairwise_distances_chunked

from .regression import explained_variance_score
from .regression import max_error
from .regression import mean_absolute_error
from .regression import mean_squared_error
from .regression import mean_squared_log_error
from .regression import median_absolute_error
from .regression import r2_score


from .scorer import check_scoring
from .scorer import make_scorer
from .scorer import SCORERS
Expand Down Expand Up @@ -99,6 +101,7 @@
'log_loss',
'make_scorer',
'matthews_corrcoef',
'max_error',
'mean_absolute_error',
'mean_squared_error',
'mean_squared_log_error',
Expand Down
35 changes: 35 additions & 0 deletions sklearn/metrics/regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@


__ALL__ = [
"max_error",
"mean_absolute_error",
"mean_squared_error",
"mean_squared_log_error",
Expand Down Expand Up @@ -573,3 +574,37 @@ def r2_score(y_true, y_pred, sample_weight=None,
avg_weights = multioutput

return np.average(output_scores, weights=avg_weights)


def max_error(y_true, y_pred):
Copy link
Member

Choose a reason for hiding this comment

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

I guess we can support sample_weight here, right?

Copy link
Contributor Author

@whiletruelearn whiletruelearn Oct 4, 2018

Choose a reason for hiding this comment

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

Thought about this for some time . Does it make sense to add? I see that median_absolute_error also doesn't accept sample weight. We are calculating the max residual error right, i couldn't fully understand the purpose sample_weight would provide here.

Copy link
Member

Choose a reason for hiding this comment

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

See #3450 and #6217

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. I have made the change. Can you please review.

"""
Copy link
Member

Choose a reason for hiding this comment

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

PEP257: put a one-line summary here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

max_error metric calculates the maximum residual error.

Read more in the :ref:`User Guide <max_error>`.

Parameters
----------
y_true : array-like of shape = (n_samples)
Ground truth (correct) target values.

y_pred : array-like of shape = (n_samples)
Estimated target values.

Returns
-------
max_error : float
A positive floating point value (the best value is 0.0).

Examples
--------
>>> from sklearn.metrics import max_error
>>> y_true = [3, 2, 7, 1]
>>> y_pred = [4, 2, 7, 1]
>>> max_error(y_true, y_pred)
1
"""
y_type, y_true, y_pred, _ = _check_reg_targets(y_true, y_pred, None)
check_consistent_length(y_true, y_pred)
if y_type == 'continuous-multioutput':
raise ValueError("Multioutput not supported in max_error")
return np.max(np.abs(y_true - y_pred))
5 changes: 4 additions & 1 deletion sklearn/metrics/scorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import numpy as np

from . import (r2_score, median_absolute_error, mean_absolute_error,
from . import (r2_score, median_absolute_error, max_error, mean_absolute_error,
mean_squared_error, mean_squared_log_error, accuracy_score,
f1_score, roc_auc_score, average_precision_score,
precision_score, recall_score, log_loss,
Expand Down Expand Up @@ -454,6 +454,8 @@ def make_scorer(score_func, greater_is_better=True, needs_proba=False,
# Standard regression scores
explained_variance_scorer = make_scorer(explained_variance_score)
r2_scorer = make_scorer(r2_score)
max_error_scorer = make_scorer(max_error,
greater_is_better=False)
neg_mean_squared_error_scorer = make_scorer(mean_squared_error,
greater_is_better=False)
neg_mean_squared_log_error_scorer = make_scorer(mean_squared_log_error,
Expand Down Expand Up @@ -498,6 +500,7 @@ def make_scorer(score_func, greater_is_better=True, needs_proba=False,

SCORERS = dict(explained_variance=explained_variance_scorer,
r2=r2_scorer,
max_error=max_error_scorer,
neg_median_absolute_error=neg_median_absolute_error_scorer,
neg_mean_absolute_error=neg_mean_absolute_error_scorer,
neg_mean_squared_error=neg_mean_squared_error_scorer,
Expand Down
5 changes: 4 additions & 1 deletion sklearn/metrics/tests/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from sklearn.metrics import label_ranking_average_precision_score
from sklearn.metrics import label_ranking_loss
from sklearn.metrics import log_loss
from sklearn.metrics import max_error
from sklearn.metrics import matthews_corrcoef
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
Expand Down Expand Up @@ -89,6 +90,7 @@
#

REGRESSION_METRICS = {
"max_error": max_error,
"mean_absolute_error": mean_absolute_error,
"mean_squared_error": mean_squared_error,
"median_absolute_error": median_absolute_error,
Expand Down Expand Up @@ -399,7 +401,7 @@ def precision_recall_curve_padded_thresholds(*args, **kwargs):
"micro_precision_score", "micro_recall_score",

"matthews_corrcoef_score", "mean_absolute_error", "mean_squared_error",
"median_absolute_error",
"median_absolute_error", "max_error",

"cohen_kappa_score",
}
Expand Down Expand Up @@ -429,6 +431,7 @@ def precision_recall_curve_padded_thresholds(*args, **kwargs):
# No Sample weight support
METRICS_WITHOUT_SAMPLE_WEIGHT = {
"median_absolute_error",
"max_error"
}


Expand Down
3 changes: 3 additions & 0 deletions sklearn/metrics/tests/test_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_squared_log_error
from sklearn.metrics import median_absolute_error
from sklearn.metrics import max_error
from sklearn.metrics import r2_score

from sklearn.metrics.regression import _check_reg_targets
Expand All @@ -29,6 +30,7 @@ def test_regression_metrics(n_samples=50):
np.log(1 + y_pred)))
assert_almost_equal(mean_absolute_error(y_true, y_pred), 1.)
assert_almost_equal(median_absolute_error(y_true, y_pred), 1.)
assert_almost_equal(max_error(y_true, y_pred), 1.)
assert_almost_equal(r2_score(y_true, y_pred), 0.995, 2)
assert_almost_equal(explained_variance_score(y_true, y_pred), 1.)

Expand Down Expand Up @@ -59,6 +61,7 @@ def test_regression_metrics_at_limits():
assert_almost_equal(mean_squared_log_error([0.], [0.]), 0.00, 2)
assert_almost_equal(mean_absolute_error([0.], [0.]), 0.00, 2)
assert_almost_equal(median_absolute_error([0.], [0.]), 0.00, 2)
assert_almost_equal(max_error([0.], [0.]), 0.00, 2)
assert_almost_equal(explained_variance_score([0.], [0.]), 1.00, 2)
assert_almost_equal(r2_score([0., 1], [0., 1]), 1.00, 2)
assert_raises_regex(ValueError, "Mean Squared Logarithmic Error cannot be "
Expand Down
3 changes: 2 additions & 1 deletion sklearn/metrics/tests/test_score_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
'neg_mean_absolute_error', 'neg_mean_squared_error',
'neg_mean_squared_log_error',
'neg_median_absolute_error', 'mean_absolute_error',
'mean_squared_error', 'median_absolute_error']
'mean_squared_error', 'median_absolute_error',
'max_error']

CLF_SCORERS = ['accuracy', 'balanced_accuracy',
'f1', 'f1_weighted', 'f1_macro', 'f1_micro',
Expand Down