Aluode/PerceptionLabPortable
0
1import copy
2import pickle
3import warnings
4
5import numpy as np
6import pytest
7from scipy.special import expit
8
9import sklearn
10from sklearn.datasets import make_regression
11from sklearn.isotonic import (
12 IsotonicRegression,
13 _make_unique,
14 check_increasing,
15 isotonic_regression,
16)
17from sklearn.utils import shuffle
18from sklearn.utils._testing import (
19 assert_allclose,
20 assert_array_almost_equal,
21 assert_array_equal,
22)
23from sklearn.utils.validation import check_array
24
25
26def test_permutation_invariance():
27 # check that fit is permutation invariant.
28 # regression test of missing sorting of sample-weights
29 ir = IsotonicRegression()
30 x = [1, 2, 3, 4, 5, 6, 7]
31 y = [1, 41, 51, 1, 2, 5, 24]
32 sample_weight = [1, 2, 3, 4, 5, 6, 7]
33 x_s, y_s, sample_weight_s = shuffle(x, y, sample_weight, random_state=0)
34 y_transformed = ir.fit_transform(x, y, sample_weight=sample_weight)
35 y_transformed_s = ir.fit(x_s, y_s, sample_weight=sample_weight_s).transform(x)
36
37 assert_array_equal(y_transformed, y_transformed_s)
38
39
40def test_check_increasing_small_number_of_samples():
41 x = [0, 1, 2]
42 y = [1, 1.1, 1.05]
43
44 with warnings.catch_warnings():
45 warnings.simplefilter("error", UserWarning)
46 is_increasing = check_increasing(x, y)
47
48 assert is_increasing
49
50
51def test_check_increasing_up():
52 x = [0, 1, 2, 3, 4, 5]
53 y = [0, 1.5, 2.77, 8.99, 8.99, 50]
54
55 # Check that we got increasing=True and no warnings
56 with warnings.catch_warnings():
57 warnings.simplefilter("error", UserWarning)
58 is_increasing = check_increasing(x, y)
59
60 assert is_increasing
61
62
63def test_check_increasing_up_extreme():
64 x = [0, 1, 2, 3, 4, 5]
65 y = [0, 1, 2, 3, 4, 5]
66
67 # Check that we got increasing=True and no warnings
68 with warnings.catch_warnings():
69 warnings.simplefilter("error", UserWarning)
70 is_increasing = check_increasing(x, y)
71
72 assert is_increasing
73
74
75def test_check_increasing_down():
76 x = [0, 1, 2, 3, 4, 5]
77 y = [0, -1.5, -2.77, -8.99, -8.99, -50]
78
79 # Check that we got increasing=False and no warnings
80 with warnings.catch_warnings():
81 warnings.simplefilter("error", UserWarning)
82 is_increasing = check_increasing(x, y)
83
84 assert not is_increasing
85
86
87def test_check_increasing_down_extreme():
88 x = [0, 1, 2, 3, 4, 5]
89 y = [0, -1, -2, -3, -4, -5]
90
91 # Check that we got increasing=False and no warnings
92 with warnings.catch_warnings():
93 warnings.simplefilter("error", UserWarning)
94 is_increasing = check_increasing(x, y)
95
96 assert not is_increasing
97
98
99def test_check_ci_warn():
100 x = [0, 1, 2, 3, 4, 5]
101 y = [0, -1, 2, -3, 4, -5]
102
103 # Check that we got increasing=False and CI interval warning
104 msg = "interval"
105 with pytest.warns(UserWarning, match=msg):
106 is_increasing = check_increasing(x, y)
107
108 assert not is_increasing
109
110
111def test_isotonic_regression():
112 y = np.array([3, 7, 5, 9, 8, 7, 10])
113 y_ = np.array([3, 6, 6, 8, 8, 8, 10])
114 assert_array_equal(y_, isotonic_regression(y))
115
116 y = np.array([10, 0, 2])
117 y_ = np.array([4, 4, 4])
118 assert_array_equal(y_, isotonic_regression(y))
119
120 x = np.arange(len(y))
121 ir = IsotonicRegression(y_min=0.0, y_max=1.0)
122 ir.fit(x, y)
123 assert_array_equal(ir.fit(x, y).transform(x), ir.fit_transform(x, y))
124 assert_array_equal(ir.transform(x), ir.predict(x))
125
126 # check that it is immune to permutation
127 perm = np.random.permutation(len(y))
128 ir = IsotonicRegression(y_min=0.0, y_max=1.0)
129 assert_array_equal(ir.fit_transform(x[perm], y[perm]), ir.fit_transform(x, y)[perm])
130 assert_array_equal(ir.transform(x[perm]), ir.transform(x)[perm])
131
132 # check we don't crash when all x are equal:
133 ir = IsotonicRegression()
134 assert_array_equal(ir.fit_transform(np.ones(len(x)), y), np.mean(y))
135
136
137def test_isotonic_regression_ties_min():
138 # Setup examples with ties on minimum
139 x = [1, 1, 2, 3, 4, 5]
140 y = [1, 2, 3, 4, 5, 6]
141 y_true = [1.5, 1.5, 3, 4, 5, 6]
142
143 # Check that we get identical results for fit/transform and fit_transform
144 ir = IsotonicRegression()
145 ir.fit(x, y)
146 assert_array_equal(ir.fit(x, y).transform(x), ir.fit_transform(x, y))
147 assert_array_equal(y_true, ir.fit_transform(x, y))
148
149
150def test_isotonic_regression_ties_max():
151 # Setup examples with ties on maximum
152 x = [1, 2, 3, 4, 5, 5]
153 y = [1, 2, 3, 4, 5, 6]
154 y_true = [1, 2, 3, 4, 5.5, 5.5]
155
156 # Check that we get identical results for fit/transform and fit_transform
157 ir = IsotonicRegression()
158 ir.fit(x, y)
159 assert_array_equal(ir.fit(x, y).transform(x), ir.fit_transform(x, y))
160 assert_array_equal(y_true, ir.fit_transform(x, y))
161
162
163def test_isotonic_regression_ties_secondary_():
164 """
165 Test isotonic regression fit, transform and fit_transform
166 against the "secondary" ties method and "pituitary" data from R
167 "isotone" package, as detailed in: J. d. Leeuw, K. Hornik, P. Mair,
168 Isotone Optimization in R: Pool-Adjacent-Violators Algorithm
169 (PAVA) and Active Set Methods
170
171 Set values based on pituitary example and
172 the following R command detailed in the paper above:
173 > library("isotone")
174 > data("pituitary")
175 > res1 <- gpava(pituitary$age, pituitary$size, ties="secondary")
176 > res1$x
177
178 `isotone` version: 1.0-2, 2014-09-07
179 R version: R version 3.1.1 (2014-07-10)
180 """
181 x = [8, 8, 8, 10, 10, 10, 12, 12, 12, 14, 14]
182 y = [21, 23.5, 23, 24, 21, 25, 21.5, 22, 19, 23.5, 25]
183 y_true = [
184 22.22222,
185 22.22222,
186 22.22222,
187 22.22222,
188 22.22222,
189 22.22222,
190 22.22222,
191 22.22222,
192 22.22222,
193 24.25,
194 24.25,
195 ]
196
197 # Check fit, transform and fit_transform
198 ir = IsotonicRegression()
199 ir.fit(x, y)
200 assert_array_almost_equal(ir.transform(x), y_true, 4)
201 assert_array_almost_equal(ir.fit_transform(x, y), y_true, 4)
202
203
204def test_isotonic_regression_with_ties_in_differently_sized_groups():
205 """
206 Non-regression test to handle issue 9432:
207 https://github.com/scikit-learn/scikit-learn/issues/9432
208
209 Compare against output in R:
210 > library("isotone")
211 > x <- c(0, 1, 1, 2, 3, 4)
212 > y <- c(0, 0, 1, 0, 0, 1)
213 > res1 <- gpava(x, y, ties="secondary")
214 > res1$x
215
216 `isotone` version: 1.1-0, 2015-07-24
217 R version: R version 3.3.2 (2016-10-31)
218 """
219 x = np.array([0, 1, 1, 2, 3, 4])
220 y = np.array([0, 0, 1, 0, 0, 1])
221 y_true = np.array([0.0, 0.25, 0.25, 0.25, 0.25, 1.0])
222 ir = IsotonicRegression()
223 ir.fit(x, y)
224 assert_array_almost_equal(ir.transform(x), y_true)
225 assert_array_almost_equal(ir.fit_transform(x, y), y_true)
226
227
228def test_isotonic_regression_reversed():
229 y = np.array([10, 9, 10, 7, 6, 6.1, 5])
230 y_result = np.array([10, 9.5, 9.5, 7, 6.05, 6.05, 5])
231
232 y_iso = isotonic_regression(y, increasing=False)
233 assert_allclose(y_iso, y_result)
234
235 y_ = IsotonicRegression(increasing=False).fit_transform(np.arange(len(y)), y)
236 assert_allclose(y_, y_result)
237 assert_array_equal(np.ones(y_[:-1].shape), ((y_[:-1] - y_[1:]) >= 0))
238
239
240def test_isotonic_regression_auto_decreasing():
241 # Set y and x for decreasing
242 y = np.array([10, 9, 10, 7, 6, 6.1, 5])
243 x = np.arange(len(y))
244
245 # Create model and fit_transform
246 ir = IsotonicRegression(increasing="auto")
247 with warnings.catch_warnings(record=True) as w:
248 warnings.simplefilter("always")
249 y_ = ir.fit_transform(x, y)
250 # work-around for pearson divide warnings in scipy <= 0.17.0
251 assert all(["invalid value encountered in " in str(warn.message) for warn in w])
252
253 # Check that relationship decreases
254 is_increasing = y_[0] < y_[-1]
255 assert not is_increasing
256
257
258def test_isotonic_regression_auto_increasing():
259 # Set y and x for decreasing
260 y = np.array([5, 6.1, 6, 7, 10, 9, 10])
261 x = np.arange(len(y))
262
263 # Create model and fit_transform
264 ir = IsotonicRegression(increasing="auto")
265 with warnings.catch_warnings(record=True) as w:
266 warnings.simplefilter("always")
267 y_ = ir.fit_transform(x, y)
268 # work-around for pearson divide warnings in scipy <= 0.17.0
269 assert all(["invalid value encountered in " in str(warn.message) for warn in w])
270
271 # Check that relationship increases
272 is_increasing = y_[0] < y_[-1]
273 assert is_increasing
274
275
276def test_assert_raises_exceptions():
277 ir = IsotonicRegression()
278 rng = np.random.RandomState(42)
279
280 msg = "Found input variables with inconsistent numbers of samples"
281 with pytest.raises(ValueError, match=msg):
282 ir.fit([0, 1, 2], [5, 7, 3], [0.1, 0.6])
283
284 with pytest.raises(ValueError, match=msg):
285 ir.fit([0, 1, 2], [5, 7])
286
287 msg = "X should be a 1d array"
288 with pytest.raises(ValueError, match=msg):
289 ir.fit(rng.randn(3, 10), [0, 1, 2])
290
291 msg = "Isotonic regression input X should be a 1d array"
292 with pytest.raises(ValueError, match=msg):
293 ir.transform(rng.randn(3, 10))
294
295
296def test_isotonic_sample_weight_parameter_default_value():
297 # check if default value of sample_weight parameter is one
298 ir = IsotonicRegression()
299 # random test data
300 rng = np.random.RandomState(42)
301 n = 100
302 x = np.arange(n)
303 y = rng.randint(-50, 50, size=(n,)) + 50.0 * np.log(1 + np.arange(n))
304 # check if value is correctly used
305 weights = np.ones(n)
306 y_set_value = ir.fit_transform(x, y, sample_weight=weights)
307 y_default_value = ir.fit_transform(x, y)
308
309 assert_array_equal(y_set_value, y_default_value)
310
311
312def test_isotonic_min_max_boundaries():
313 # check if min value is used correctly
314 ir = IsotonicRegression(y_min=2, y_max=4)
315 n = 6
316 x = np.arange(n)
317 y = np.arange(n)
318 y_test = [2, 2, 2, 3, 4, 4]
319 y_result = np.round(ir.fit_transform(x, y))
320 assert_array_equal(y_result, y_test)
321
322
323def test_isotonic_sample_weight():
324 ir = IsotonicRegression()
325 x = [1, 2, 3, 4, 5, 6, 7]
326 y = [1, 41, 51, 1, 2, 5, 24]
327 sample_weight = [1, 2, 3, 4, 5, 6, 7]
328 expected_y = [1, 13.95, 13.95, 13.95, 13.95, 13.95, 24]
329 received_y = ir.fit_transform(x, y, sample_weight=sample_weight)
330
331 assert_array_equal(expected_y, received_y)
332
333
334def test_isotonic_regression_oob_raise():
335 # Set y and x
336 y = np.array([3, 7, 5, 9, 8, 7, 10])
337 x = np.arange(len(y))
338
339 # Create model and fit
340 ir = IsotonicRegression(increasing="auto", out_of_bounds="raise")
341 ir.fit(x, y)
342
343 # Check that an exception is thrown
344 msg = "in x_new is below the interpolation range"
345 with pytest.raises(ValueError, match=msg):
346 ir.predict([min(x) - 10, max(x) + 10])
347
348
349def test_isotonic_regression_oob_clip():
350 # Set y and x
351 y = np.array([3, 7, 5, 9, 8, 7, 10])
352 x = np.arange(len(y))
353
354 # Create model and fit
355 ir = IsotonicRegression(increasing="auto", out_of_bounds="clip")
356 ir.fit(x, y)
357
358 # Predict from training and test x and check that min/max match.
359 y1 = ir.predict([min(x) - 10, max(x) + 10])
360 y2 = ir.predict(x)
361 assert max(y1) == max(y2)
362 assert min(y1) == min(y2)
363
364
365def test_isotonic_regression_oob_nan():
366 # Set y and x
367 y = np.array([3, 7, 5, 9, 8, 7, 10])
368 x = np.arange(len(y))
369
370 # Create model and fit
371 ir = IsotonicRegression(increasing="auto", out_of_bounds="nan")
372 ir.fit(x, y)
373
374 # Predict from training and test x and check that we have two NaNs.
375 y1 = ir.predict([min(x) - 10, max(x) + 10])
376 assert sum(np.isnan(y1)) == 2
377
378
379def test_isotonic_regression_pickle():
380 y = np.array([3, 7, 5, 9, 8, 7, 10])
381 x = np.arange(len(y))
382
383 # Create model and fit
384 ir = IsotonicRegression(increasing="auto", out_of_bounds="clip")
385 ir.fit(x, y)
386
387 ir_ser = pickle.dumps(ir, pickle.HIGHEST_PROTOCOL)
388 ir2 = pickle.loads(ir_ser)
389 np.testing.assert_array_equal(ir.predict(x), ir2.predict(x))
390
391
392def test_isotonic_duplicate_min_entry():
393 x = [0, 0, 1]
394 y = [0, 0, 1]
395
396 ir = IsotonicRegression(increasing=True, out_of_bounds="clip")
397 ir.fit(x, y)
398 all_predictions_finite = np.all(np.isfinite(ir.predict(x)))
399 assert all_predictions_finite
400
401
402def test_isotonic_ymin_ymax():
403 # Test from @NelleV's issue:
404 # https://github.com/scikit-learn/scikit-learn/issues/6921
405 x = np.array(
406 [
407 1.263,
408 1.318,
409 -0.572,
410 0.307,
411 -0.707,
412 -0.176,
413 -1.599,
414 1.059,
415 1.396,
416 1.906,
417 0.210,
418 0.028,
419 -0.081,
420 0.444,
421 0.018,
422 -0.377,
423 -0.896,
424 -0.377,
425 -1.327,
426 0.180,
427 ]
428 )
429 y = isotonic_regression(x, y_min=0.0, y_max=0.1)
430
431 assert np.all(y >= 0)
432 assert np.all(y <= 0.1)
433
434 # Also test decreasing case since the logic there is different
435 y = isotonic_regression(x, y_min=0.0, y_max=0.1, increasing=False)
436
437 assert np.all(y >= 0)
438 assert np.all(y <= 0.1)
439
440 # Finally, test with only one bound
441 y = isotonic_regression(x, y_min=0.0, increasing=False)
442
443 assert np.all(y >= 0)
444
445
446def test_isotonic_zero_weight_loop():
447 # Test from @ogrisel's issue:
448 # https://github.com/scikit-learn/scikit-learn/issues/4297
449
450 # Get deterministic RNG with seed
451 rng = np.random.RandomState(42)
452
453 # Create regression and samples
454 regression = IsotonicRegression()
455 n_samples = 50
456 x = np.linspace(-3, 3, n_samples)
457 y = x + rng.uniform(size=n_samples)
458
459 # Get some random weights and zero out
460 w = rng.uniform(size=n_samples)
461 w[5:8] = 0
462 regression.fit(x, y, sample_weight=w)
463
464 # This will hang in failure case.
465 regression.fit(x, y, sample_weight=w)
466
467
468def test_fast_predict():
469 # test that the faster prediction change doesn't
470 # affect out-of-sample predictions:
471 # https://github.com/scikit-learn/scikit-learn/pull/6206
472 rng = np.random.RandomState(123)
473 n_samples = 10**3
474 # X values over the -10,10 range
475 X_train = 20.0 * rng.rand(n_samples) - 10
476 y_train = (
477 np.less(rng.rand(n_samples), expit(X_train)).astype("int64").astype("float64")
478 )
479
480 weights = rng.rand(n_samples)
481 # we also want to test that everything still works when some weights are 0
482 weights[rng.rand(n_samples) < 0.1] = 0
483
484 slow_model = IsotonicRegression(y_min=0, y_max=1, out_of_bounds="clip")
485 fast_model = IsotonicRegression(y_min=0, y_max=1, out_of_bounds="clip")
486
487 # Build interpolation function with ALL input data, not just the
488 # non-redundant subset. The following 2 lines are taken from the
489 # .fit() method, without removing unnecessary points
490 X_train_fit, y_train_fit = slow_model._build_y(
491 X_train, y_train, sample_weight=weights, trim_duplicates=False
492 )
493 slow_model._build_f(X_train_fit, y_train_fit)
494
495 # fit with just the necessary data
496 fast_model.fit(X_train, y_train, sample_weight=weights)
497
498 X_test = 20.0 * rng.rand(n_samples) - 10
499 y_pred_slow = slow_model.predict(X_test)
500 y_pred_fast = fast_model.predict(X_test)
501
502 assert_array_equal(y_pred_slow, y_pred_fast)
503
504
505def test_isotonic_copy_before_fit():
506 # https://github.com/scikit-learn/scikit-learn/issues/6628
507 ir = IsotonicRegression()
508 copy.copy(ir)
509
510
511@pytest.mark.parametrize("dtype", [np.int32, np.int64, np.float32, np.float64])
512def test_isotonic_dtype(dtype):
513 y = [2, 1, 4, 3, 5]
514 weights = np.array([0.9, 0.9, 0.9, 0.9, 0.9], dtype=np.float64)
515 reg = IsotonicRegression()
516
517 for sample_weight in (None, weights.astype(np.float32), weights):
518 y_np = np.array(y, dtype=dtype)
519 expected_dtype = check_array(
520 y_np, dtype=[np.float64, np.float32], ensure_2d=False
521 ).dtype
522
523 res = isotonic_regression(y_np, sample_weight=sample_weight)
524 assert res.dtype == expected_dtype
525
526 X = np.arange(len(y)).astype(dtype)
527 reg.fit(X, y_np, sample_weight=sample_weight)
528 res = reg.predict(X)
529 assert res.dtype == expected_dtype
530
531
532@pytest.mark.parametrize("y_dtype", [np.int32, np.int64, np.float32, np.float64])
533def test_isotonic_mismatched_dtype(y_dtype):
534 # regression test for #15004
535 # check that data are converted when X and y dtype differ
536 reg = IsotonicRegression()
537 y = np.array([2, 1, 4, 3, 5], dtype=y_dtype)
538 X = np.arange(len(y), dtype=np.float32)
539 reg.fit(X, y)
540 assert reg.predict(X).dtype == X.dtype
541
542
543def test_make_unique_dtype():
544 x_list = [2, 2, 2, 3, 5]
545 for dtype in (np.float32, np.float64):
546 x = np.array(x_list, dtype=dtype)
547 y = x.copy()
548 w = np.ones_like(x)
549 x, y, w = _make_unique(x, y, w)
550 assert_array_equal(x, [2, 3, 5])
551
552
553@pytest.mark.parametrize("dtype", [np.float64, np.float32])
554def test_make_unique_tolerance(dtype):
555 # Check that equality takes account of np.finfo tolerance
556 x = np.array([0, 1e-16, 1, 1 + 1e-14], dtype=dtype)
557 y = x.copy()
558 w = np.ones_like(x)
559 x, y, w = _make_unique(x, y, w)
560 if dtype == np.float64:
561 x_out = np.array([0, 1, 1 + 1e-14])
562 else:
563 x_out = np.array([0, 1])
564 assert_array_equal(x, x_out)
565
566
567def test_isotonic_make_unique_tolerance():
568 # Check that averaging of targets for duplicate X is done correctly,
569 # taking into account tolerance
570 X = np.array([0, 1, 1 + 1e-16, 2], dtype=np.float64)
571 y = np.array([0, 1, 2, 3], dtype=np.float64)
572 ireg = IsotonicRegression().fit(X, y)
573 y_pred = ireg.predict([0, 0.5, 1, 1.5, 2])
574
575 assert_array_equal(y_pred, np.array([0, 0.75, 1.5, 2.25, 3]))
576 assert_array_equal(ireg.X_thresholds_, np.array([0.0, 1.0, 2.0]))
577 assert_array_equal(ireg.y_thresholds_, np.array([0.0, 1.5, 3.0]))
578
579
580def test_isotonic_non_regression_inf_slope():
581 # Non-regression test to ensure that inf values are not returned
582 # see: https://github.com/scikit-learn/scikit-learn/issues/10903
583 X = np.array([0.0, 4.1e-320, 4.4e-314, 1.0])
584 y = np.array([0.42, 0.42, 0.44, 0.44])
585 ireg = IsotonicRegression().fit(X, y)
586 y_pred = ireg.predict(np.array([0, 2.1e-319, 5.4e-316, 1e-10]))
587 assert np.all(np.isfinite(y_pred))
588
589
590@pytest.mark.parametrize("increasing", [True, False])
591def test_isotonic_thresholds(increasing):
592 rng = np.random.RandomState(42)
593 n_samples = 30
594 X = rng.normal(size=n_samples)
595 y = rng.normal(size=n_samples)
596 ireg = IsotonicRegression(increasing=increasing).fit(X, y)
597 X_thresholds, y_thresholds = ireg.X_thresholds_, ireg.y_thresholds_
598 assert X_thresholds.shape == y_thresholds.shape
599
600 # Input thresholds are a strict subset of the training set (unless
601 # the data is already strictly monotonic which is not the case with
602 # this random data)
603 assert X_thresholds.shape[0] < X.shape[0]
604 assert np.isin(X_thresholds, X).all()
605
606 # Output thresholds lie in the range of the training set:
607 assert y_thresholds.max() <= y.max()
608 assert y_thresholds.min() >= y.min()
609
610 assert all(np.diff(X_thresholds) > 0)
611 if increasing:
612 assert all(np.diff(y_thresholds) >= 0)
613 else:
614 assert all(np.diff(y_thresholds) <= 0)
615
616
617def test_input_shape_validation():
618 # Test from #15012
619 # Check that IsotonicRegression can handle 2darray with only 1 feature
620 X = np.arange(10)
621 X_2d = X.reshape(-1, 1)
622 y = np.arange(10)
623
624 iso_reg = IsotonicRegression().fit(X, y)
625 iso_reg_2d = IsotonicRegression().fit(X_2d, y)
626
627 assert iso_reg.X_max_ == iso_reg_2d.X_max_
628 assert iso_reg.X_min_ == iso_reg_2d.X_min_
629 assert iso_reg.y_max == iso_reg_2d.y_max
630 assert iso_reg.y_min == iso_reg_2d.y_min
631 assert_array_equal(iso_reg.X_thresholds_, iso_reg_2d.X_thresholds_)
632 assert_array_equal(iso_reg.y_thresholds_, iso_reg_2d.y_thresholds_)
633
634 y_pred1 = iso_reg.predict(X)
635 y_pred2 = iso_reg_2d.predict(X_2d)
636 assert_allclose(y_pred1, y_pred2)
637
638
639def test_isotonic_2darray_more_than_1_feature():
640 # Ensure IsotonicRegression raises error if input has more than 1 feature
641 X = np.arange(10)
642 X_2d = np.c_[X, X]
643 y = np.arange(10)
644
645 msg = "should be a 1d array or 2d array with 1 feature"
646 with pytest.raises(ValueError, match=msg):
647 IsotonicRegression().fit(X_2d, y)
648
649 iso_reg = IsotonicRegression().fit(X, y)
650 with pytest.raises(ValueError, match=msg):
651 iso_reg.predict(X_2d)
652
653 with pytest.raises(ValueError, match=msg):
654 iso_reg.transform(X_2d)
655
656
657def test_isotonic_regression_sample_weight_not_overwritten():
658 """Check that calling fitting function of isotonic regression will not
659 overwrite `sample_weight`.
660 Non-regression test for:
661 https://github.com/scikit-learn/scikit-learn/issues/20508
662 """
663 X, y = make_regression(n_samples=10, n_features=1, random_state=41)
664 sample_weight_original = np.ones_like(y)
665 sample_weight_original[0] = 10
666 sample_weight_fit = sample_weight_original.copy()
667
668 isotonic_regression(y, sample_weight=sample_weight_fit)
669 assert_allclose(sample_weight_fit, sample_weight_original)
670
671 IsotonicRegression().fit(X, y, sample_weight=sample_weight_fit)
672 assert_allclose(sample_weight_fit, sample_weight_original)
673
674
675@pytest.mark.parametrize("shape", ["1d", "2d"])
676def test_get_feature_names_out(shape):
677 """Check `get_feature_names_out` for `IsotonicRegression`."""
678 X = np.arange(10)
679 if shape == "2d":
680 X = X.reshape(-1, 1)
681 y = np.arange(10)
682
683 iso = IsotonicRegression().fit(X, y)
684 names = iso.get_feature_names_out()
685 assert isinstance(names, np.ndarray)
686 assert names.dtype == object
687 assert_array_equal(["isotonicregression0"], names)
688
689
690def test_isotonic_regression_output_predict():
691 """Check that `predict` does return the expected output type.
692
693 We need to check that `transform` will output a DataFrame and a NumPy array
694 when we set `transform_output` to `pandas`.
695
696 Non-regression test for:
697 https://github.com/scikit-learn/scikit-learn/issues/25499
698 """
699 pd = pytest.importorskip("pandas")
700 X, y = make_regression(n_samples=10, n_features=1, random_state=42)
701 regressor = IsotonicRegression()
702 with sklearn.config_context(transform_output="pandas"):
703 regressor.fit(X, y)
704 X_trans = regressor.transform(X)
705 y_pred = regressor.predict(X)
706
707 assert isinstance(X_trans, pd.DataFrame)
708 assert isinstance(y_pred, np.ndarray)
709 