Skip to content

Commit a546e1a

Browse files
bnaulagramfort
authored andcommitted
Properly handle bounds in isotonic regression with np.clip (scikit-learn#6949)
1 parent 3f37cb9 commit a546e1a

File tree

2 files changed

+34
-16
lines changed

2 files changed

+34
-16
lines changed

sklearn/isotonic.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,24 +129,19 @@ def isotonic_regression(y, sample_weight=None, y_min=None, y_max=None,
129129
y = y[::-1]
130130
sample_weight = sample_weight[::-1]
131131

132-
if y_min is not None or y_max is not None:
133-
y = np.copy(y)
134-
sample_weight = np.copy(sample_weight)
135-
# upper bound on the cost function
136-
C = np.dot(sample_weight, y * y) * 10
137-
if y_min is not None:
138-
y[0] = y_min
139-
sample_weight[0] = C
140-
if y_max is not None:
141-
y[-1] = y_max
142-
sample_weight[-1] = C
143-
144132
solution = np.empty(len(y))
145133
y_ = _isotonic_regression(y, sample_weight, solution)
146-
if increasing:
147-
return y_
148-
else:
149-
return y_[::-1]
134+
if not increasing:
135+
y_ = y_[::-1]
136+
137+
if y_min is not None or y_max is not None:
138+
# Older versions of np.clip don't accept None as a bound, so use np.inf
139+
if y_min is None:
140+
y_min = -np.inf
141+
if y_max is None:
142+
y_max = np.inf
143+
np.clip(y_, y_min, y_max, y_)
144+
return y_
150145

151146

152147
class IsotonicRegression(BaseEstimator, TransformerMixin, RegressorMixin):

sklearn/tests/test_isotonic.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,29 @@ def test_isotonic_duplicate_min_entry():
338338
assert_true(all_predictions_finite)
339339

340340

341+
def test_isotonic_ymin_ymax():
342+
# Test from @NelleV's issue:
343+
# https://github.com/scikit-learn/scikit-learn/issues/6921
344+
x = np.array([1.263, 1.318, -0.572, 0.307, -0.707, -0.176, -1.599, 1.059,
345+
1.396, 1.906, 0.210, 0.028, -0.081, 0.444, 0.018, -0.377,
346+
-0.896, -0.377, -1.327, 0.180])
347+
y = isotonic_regression(x, y_min=0., y_max=0.1)
348+
349+
assert(np.all(y >= 0))
350+
assert(np.all(y <= 0.1))
351+
352+
# Also test decreasing case since the logic there is different
353+
y = isotonic_regression(x, y_min=0., y_max=0.1, increasing=False)
354+
355+
assert(np.all(y >= 0))
356+
assert(np.all(y <= 0.1))
357+
358+
# Finally, test with only one bound
359+
y = isotonic_regression(x, y_min=0., increasing=False)
360+
361+
assert(np.all(y >= 0))
362+
363+
341364
def test_isotonic_zero_weight_loop():
342365
# Test from @ogrisel's issue:
343366
# https://github.com/scikit-learn/scikit-learn/issues/4297

0 commit comments

Comments
 (0)