CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
test_multiclass.py646 linesDownload Raw Back to tests
1import warnings
2from itertools import product
3
4import numpy as np
5import pytest
6from scipy.sparse import issparse
7
8from sklearn import config_context, datasets
9from sklearn.model_selection import ShuffleSplit
10from sklearn.svm import SVC
11from sklearn.utils._array_api import (
12    _get_namespace_device_dtype_ids,
13    yield_namespace_device_dtype_combinations,
14)
15from sklearn.utils._testing import (
16    _array_api_for_tests,
17    _convert_container,
18    assert_allclose,
19    assert_array_almost_equal,
20    assert_array_equal,
21)
22from sklearn.utils.estimator_checks import _NotAnArray
23from sklearn.utils.fixes import (
24    COO_CONTAINERS,
25    CSC_CONTAINERS,
26    CSR_CONTAINERS,
27    DOK_CONTAINERS,
28    LIL_CONTAINERS,
29)
30from sklearn.utils.metaestimators import _safe_split
31from sklearn.utils.multiclass import (
32    _ovr_decision_function,
33    check_classification_targets,
34    class_distribution,
35    is_multilabel,
36    type_of_target,
37    unique_labels,
38)
39
40multilabel_explicit_zero = np.array([[0, 1], [1, 0]])
41multilabel_explicit_zero[:, 0] = 0
42
43
44def _generate_sparse(
45    data,
46    sparse_containers=tuple(
47        COO_CONTAINERS
48        + CSC_CONTAINERS
49        + CSR_CONTAINERS
50        + DOK_CONTAINERS
51        + LIL_CONTAINERS
52    ),
53    dtypes=(bool, int, np.int8, np.uint8, float, np.float32),
54):
55    return [
56        sparse_container(data, dtype=dtype)
57        for sparse_container in sparse_containers
58        for dtype in dtypes
59    ]
60
61
62EXAMPLES = {
63    "multilabel-indicator": [
64        # valid when the data is formatted as sparse or dense, identified
65        # by CSR format when the testing takes place
66        *_generate_sparse(
67            np.random.RandomState(42).randint(2, size=(10, 10)),
68            sparse_containers=CSR_CONTAINERS,
69            dtypes=(int,),
70        ),
71        [[0, 1], [1, 0]],
72        [[0, 1]],
73        *_generate_sparse(
74            multilabel_explicit_zero, sparse_containers=CSC_CONTAINERS, dtypes=(int,)
75        ),
76        *_generate_sparse([[0, 1], [1, 0]]),
77        *_generate_sparse([[0, 0], [0, 0]]),
78        *_generate_sparse([[0, 1]]),
79        # Only valid when data is dense
80        [[-1, 1], [1, -1]],
81        np.array([[-1, 1], [1, -1]]),
82        np.array([[-3, 3], [3, -3]]),
83        _NotAnArray(np.array([[-3, 3], [3, -3]])),
84    ],
85    "multiclass": [
86        [1, 0, 2, 2, 1, 4, 2, 4, 4, 4],
87        np.array([1, 0, 2]),
88        np.array([1, 0, 2], dtype=np.int8),
89        np.array([1, 0, 2], dtype=np.uint8),
90        np.array([1, 0, 2], dtype=float),
91        np.array([1, 0, 2], dtype=np.float32),
92        np.array([[1], [0], [2]]),
93        _NotAnArray(np.array([1, 0, 2])),
94        [0, 1, 2],
95        ["a", "b", "c"],
96        np.array(["a", "b", "c"]),
97        np.array(["a", "b", "c"], dtype=object),
98        np.array(["a", "b", "c"], dtype=object),
99    ],
100    "multiclass-multioutput": [
101        [[1, 0, 2, 2], [1, 4, 2, 4]],
102        [["a", "b"], ["c", "d"]],
103        np.array([[1, 0, 2, 2], [1, 4, 2, 4]]),
104        np.array([[1, 0, 2, 2], [1, 4, 2, 4]], dtype=np.int8),
105        np.array([[1, 0, 2, 2], [1, 4, 2, 4]], dtype=np.uint8),
106        np.array([[1, 0, 2, 2], [1, 4, 2, 4]], dtype=float),
107        np.array([[1, 0, 2, 2], [1, 4, 2, 4]], dtype=np.float32),
108        *_generate_sparse(
109            [[1, 0, 2, 2], [1, 4, 2, 4]],
110            sparse_containers=CSC_CONTAINERS + CSR_CONTAINERS,
111            dtypes=(int, np.int8, np.uint8, float, np.float32),
112        ),
113        np.array([["a", "b"], ["c", "d"]]),
114        np.array([["a", "b"], ["c", "d"]]),
115        np.array([["a", "b"], ["c", "d"]], dtype=object),
116        np.array([[1, 0, 2]]),
117        _NotAnArray(np.array([[1, 0, 2]])),
118    ],
119    "binary": [
120        [0, 1],
121        [1, 1],
122        [],
123        [0],
124        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1]),
125        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1], dtype=bool),
126        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1], dtype=np.int8),
127        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1], dtype=np.uint8),
128        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1], dtype=float),
129        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1], dtype=np.float32),
130        np.array([[0], [1]]),
131        _NotAnArray(np.array([[0], [1]])),
132        [1, -1],
133        [3, 5],
134        ["a"],
135        ["a", "b"],
136        ["abc", "def"],
137        np.array(["abc", "def"]),
138        ["a", "b"],
139        np.array(["abc", "def"], dtype=object),
140    ],
141    "continuous": [
142        [1e-5],
143        [0, 0.5],
144        np.array([[0], [0.5]]),
145        np.array([[0], [0.5]], dtype=np.float32),
146    ],
147    "continuous-multioutput": [
148        np.array([[0, 0.5], [0.5, 0]]),
149        np.array([[0, 0.5], [0.5, 0]], dtype=np.float32),
150        np.array([[0, 0.5]]),
151        *_generate_sparse(
152            [[0, 0.5], [0.5, 0]],
153            sparse_containers=CSC_CONTAINERS + CSR_CONTAINERS,
154            dtypes=(float, np.float32),
155        ),
156        *_generate_sparse(
157            [[0, 0.5]],
158            sparse_containers=CSC_CONTAINERS + CSR_CONTAINERS,
159            dtypes=(float, np.float32),
160        ),
161    ],
162    "unknown": [
163        [[]],
164        np.array([[]], dtype=object),
165        [()],
166        # sequence of sequences that weren't supported even before deprecation
167        np.array([np.array([]), np.array([1, 2, 3])], dtype=object),
168        [np.array([]), np.array([1, 2, 3])],
169        [{1, 2, 3}, {1, 2}],
170        [frozenset([1, 2, 3]), frozenset([1, 2])],
171        # and also confusable as sequences of sequences
172        [{0: "a", 1: "b"}, {0: "a"}],
173        # ndim 0
174        np.array(0),
175        # empty second dimension
176        np.array([[], []]),
177        # 3d
178        np.array([[[0, 1], [2, 3]], [[4, 5], [6, 7]]]),
179    ],
180}
181
182ARRAY_API_EXAMPLES = {
183    "multilabel-indicator": [
184        np.random.RandomState(42).randint(2, size=(10, 10)),
185        [[0, 1], [1, 0]],
186        [[0, 1]],
187        multilabel_explicit_zero,
188        [[0, 0], [0, 0]],
189        [[-1, 1], [1, -1]],
190        np.array([[-1, 1], [1, -1]]),
191        np.array([[-3, 3], [3, -3]]),
192        _NotAnArray(np.array([[-3, 3], [3, -3]])),
193    ],
194    "multiclass": [
195        [1, 0, 2, 2, 1, 4, 2, 4, 4, 4],
196        np.array([1, 0, 2]),
197        np.array([1, 0, 2], dtype=np.int8),
198        np.array([1, 0, 2], dtype=np.uint8),
199        np.array([1, 0, 2], dtype=float),
200        np.array([1, 0, 2], dtype=np.float32),
201        np.array([[1], [0], [2]]),
202        _NotAnArray(np.array([1, 0, 2])),
203        [0, 1, 2],
204    ],
205    "multiclass-multioutput": [
206        [[1, 0, 2, 2], [1, 4, 2, 4]],
207        np.array([[1, 0, 2, 2], [1, 4, 2, 4]]),
208        np.array([[1, 0, 2, 2], [1, 4, 2, 4]], dtype=np.int8),
209        np.array([[1, 0, 2, 2], [1, 4, 2, 4]], dtype=np.uint8),
210        np.array([[1, 0, 2, 2], [1, 4, 2, 4]], dtype=float),
211        np.array([[1, 0, 2, 2], [1, 4, 2, 4]], dtype=np.float32),
212        np.array([[1, 0, 2]]),
213        _NotAnArray(np.array([[1, 0, 2]])),
214    ],
215    "binary": [
216        [0, 1],
217        [1, 1],
218        [],
219        [0],
220        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1]),
221        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1], dtype=bool),
222        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1], dtype=np.int8),
223        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1], dtype=np.uint8),
224        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1], dtype=float),
225        np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 1], dtype=np.float32),
226        np.array([[0], [1]]),
227        _NotAnArray(np.array([[0], [1]])),
228        [1, -1],
229        [3, 5],
230    ],
231    "continuous": [
232        [1e-5],
233        [0, 0.5],
234        np.array([[0], [0.5]]),
235        np.array([[0], [0.5]], dtype=np.float32),
236    ],
237    "continuous-multioutput": [
238        np.array([[0, 0.5], [0.5, 0]]),
239        np.array([[0, 0.5], [0.5, 0]], dtype=np.float32),
240        np.array([[0, 0.5]]),
241    ],
242    "unknown": [
243        [[]],
244        [()],
245        np.array(0),
246        np.array([[[0, 1], [2, 3]], [[4, 5], [6, 7]]]),
247    ],
248}
249
250
251NON_ARRAY_LIKE_EXAMPLES = [
252    {1, 2, 3},
253    {0: "a", 1: "b"},
254    {0: [5], 1: [5]},
255    "abc",
256    frozenset([1, 2, 3]),
257    None,
258]
259
260MULTILABEL_SEQUENCES = [
261    [[1], [2], [0, 1]],
262    [(), (2), (0, 1)],
263    np.array([[], [1, 2]], dtype="object"),
264    _NotAnArray(np.array([[], [1, 2]], dtype="object")),
265]
266
267
268def test_unique_labels():
269    # Empty iterable
270    with pytest.raises(ValueError):
271        unique_labels()
272
273    # Multiclass problem
274    assert_array_equal(unique_labels(range(10)), np.arange(10))
275    assert_array_equal(unique_labels(np.arange(10)), np.arange(10))
276    assert_array_equal(unique_labels([4, 0, 2]), np.array([0, 2, 4]))
277
278    # Multilabel indicator
279    assert_array_equal(
280        unique_labels(np.array([[0, 0, 1], [1, 0, 1], [0, 0, 0]])), np.arange(3)
281    )
282
283    assert_array_equal(unique_labels(np.array([[0, 0, 1], [0, 0, 0]])), np.arange(3))
284
285    # Several arrays passed
286    assert_array_equal(unique_labels([4, 0, 2], range(5)), np.arange(5))
287    assert_array_equal(unique_labels((0, 1, 2), (0,), (2, 1)), np.arange(3))
288
289    # Border line case with binary indicator matrix
290    with pytest.raises(ValueError):
291        unique_labels([4, 0, 2], np.ones((5, 5)))
292    with pytest.raises(ValueError):
293        unique_labels(np.ones((5, 4)), np.ones((5, 5)))
294
295    assert_array_equal(unique_labels(np.ones((4, 5)), np.ones((5, 5))), np.arange(5))
296
297
298def test_type_of_target_too_many_unique_classes():
299    """Check that we raise a warning when the number of unique classes is greater than
300    50% of the number of samples.
301
302    We need to check that we don't raise if we have less than 20 samples.
303    """
304
305    # Create array of unique labels, except '0', which appears twice.
306    # This does raise a warning.
307    # Note warning would not be raised if we passed only unique
308    # labels, which happens when `type_of_target` is passed `classes_`.
309    y = np.hstack((np.arange(20), [0]))
310    msg = r"The number of unique classes is greater than 50% of the number of samples."
311    with pytest.warns(UserWarning, match=msg):
312        type_of_target(y)
313
314    # less than 20 samples, no warning should be raised
315    y = np.arange(10)
316    with warnings.catch_warnings():
317        warnings.simplefilter("error")
318        type_of_target(y)
319
320    # More than 20 samples but only unique classes, simulating passing
321    # `classes_` to `type_of_target` (when number of classes is large).
322    # No warning should be raised
323    y = np.arange(25)
324    with warnings.catch_warnings():
325        warnings.simplefilter("ignore", UserWarning)
326        type_of_target(y)
327
328
329def test_unique_labels_non_specific():
330    # Test unique_labels with a variety of collected examples
331
332    # Smoke test for all supported format
333    for format in ["binary", "multiclass", "multilabel-indicator"]:
334        for y in EXAMPLES[format]:
335            unique_labels(y)
336
337    # We don't support those format at the moment
338    for example in NON_ARRAY_LIKE_EXAMPLES:
339        with pytest.raises(ValueError):
340            unique_labels(example)
341
342    for y_type in [
343        "unknown",
344        "continuous",
345        "continuous-multioutput",
346        "multiclass-multioutput",
347    ]:
348        for example in EXAMPLES[y_type]:
349            with pytest.raises(ValueError):
350                unique_labels(example)
351
352
353def test_unique_labels_mixed_types():
354    # Mix with binary or multiclass and multilabel
355    mix_clf_format = product(
356        EXAMPLES["multilabel-indicator"], EXAMPLES["multiclass"] + EXAMPLES["binary"]
357    )
358
359    for y_multilabel, y_multiclass in mix_clf_format:
360        with pytest.raises(ValueError):
361            unique_labels(y_multiclass, y_multilabel)
362        with pytest.raises(ValueError):
363            unique_labels(y_multilabel, y_multiclass)
364
365    with pytest.raises(ValueError):
366        unique_labels([[1, 2]], [["a", "d"]])
367
368    with pytest.raises(ValueError):
369        unique_labels(["1", 2])
370
371    with pytest.raises(ValueError):
372        unique_labels([["1", 2], [1, 3]])
373
374    with pytest.raises(ValueError):
375        unique_labels([["1", "2"], [2, 3]])
376
377
378def test_is_multilabel():
379    for group, group_examples in EXAMPLES.items():
380        dense_exp = group == "multilabel-indicator"
381
382        for example in group_examples:
383            # Only mark explicitly defined sparse examples as valid sparse
384            # multilabel-indicators
385            sparse_exp = dense_exp and issparse(example)
386
387            if issparse(example) or (
388                hasattr(example, "__array__")
389                and np.asarray(example).ndim == 2
390                and np.asarray(example).dtype.kind in "biuf"
391                and np.asarray(example).shape[1] > 0
392            ):
393                examples_sparse = [
394                    sparse_container(example)
395                    for sparse_container in (
396                        COO_CONTAINERS
397                        + CSC_CONTAINERS
398                        + CSR_CONTAINERS
399                        + DOK_CONTAINERS
400                        + LIL_CONTAINERS
401                    )
402                ]
403                for exmpl_sparse in examples_sparse:
404                    assert sparse_exp == is_multilabel(exmpl_sparse), (
405                        f"is_multilabel({exmpl_sparse!r}) should be {sparse_exp}"
406                    )
407
408            # Densify sparse examples before testing
409            if issparse(example):
410                example = example.toarray()
411
412            assert dense_exp == is_multilabel(example), (
413                f"is_multilabel({example!r}) should be {dense_exp}"
414            )
415
416
417@pytest.mark.parametrize(
418    "array_namespace, device, dtype_name",
419    yield_namespace_device_dtype_combinations(),
420    ids=_get_namespace_device_dtype_ids,
421)
422def test_is_multilabel_array_api_compliance(array_namespace, device, dtype_name):
423    xp = _array_api_for_tests(array_namespace, device)
424
425    for group, group_examples in ARRAY_API_EXAMPLES.items():
426        dense_exp = group == "multilabel-indicator"
427        for example in group_examples:
428            if np.asarray(example).dtype.kind == "f":
429                example = np.asarray(example, dtype=dtype_name)
430            else:
431                example = np.asarray(example)
432            example = xp.asarray(example, device=device)
433
434            with config_context(array_api_dispatch=True):
435                assert dense_exp == is_multilabel(example), (
436                    f"is_multilabel({example!r}) should be {dense_exp}"
437                )
438
439
440def test_check_classification_targets():
441    for y_type in EXAMPLES.keys():
442        if y_type in ["unknown", "continuous", "continuous-multioutput"]:
443            for example in EXAMPLES[y_type]:
444                msg = "Unknown label type: "
445                with pytest.raises(ValueError, match=msg):
446                    check_classification_targets(example)
447        else:
448            for example in EXAMPLES[y_type]:
449                check_classification_targets(example)
450
451
452def test_type_of_target():
453    for group, group_examples in EXAMPLES.items():
454        for example in group_examples:
455            assert type_of_target(example) == group, (
456                "type_of_target(%r) should be %r, got %r"
457                % (
458                    example,
459                    group,
460                    type_of_target(example),
461                )
462            )
463
464    for example in NON_ARRAY_LIKE_EXAMPLES:
465        msg_regex = r"Expected array-like \(array or non-string sequence\).*"
466        with pytest.raises(ValueError, match=msg_regex):
467            type_of_target(example)
468
469    for example in MULTILABEL_SEQUENCES:
470        msg = (
471            "You appear to be using a legacy multi-label data "
472            "representation. Sequence of sequences are no longer supported;"
473            " use a binary array or sparse matrix instead."
474        )
475        with pytest.raises(ValueError, match=msg):
476            type_of_target(example)
477
478
479def test_type_of_target_pandas_sparse():
480    pd = pytest.importorskip("pandas")
481
482    y = pd.arrays.SparseArray([1, np.nan, np.nan, 1, np.nan])
483    msg = "y cannot be class 'SparseSeries' or 'SparseArray'"
484    with pytest.raises(ValueError, match=msg):
485        type_of_target(y)
486
487
488def test_type_of_target_pandas_nullable():
489    """Check that type_of_target works with pandas nullable dtypes."""
490    pd = pytest.importorskip("pandas")
491
492    for dtype in ["Int32", "Float32"]:
493        y_true = pd.Series([1, 0, 2, 3, 4], dtype=dtype)
494        assert type_of_target(y_true) == "multiclass"
495
496        y_true = pd.Series([1, 0, 1, 0], dtype=dtype)
497        assert type_of_target(y_true) == "binary"
498
499    y_true = pd.DataFrame([[1.4, 3.1], [3.1, 1.4]], dtype="Float32")
500    assert type_of_target(y_true) == "continuous-multioutput"
501
502    y_true = pd.DataFrame([[0, 1], [1, 1]], dtype="Int32")
503    assert type_of_target(y_true) == "multilabel-indicator"
504
505    y_true = pd.DataFrame([[1, 2], [3, 1]], dtype="Int32")
506    assert type_of_target(y_true) == "multiclass-multioutput"
507
508
509@pytest.mark.parametrize("dtype", ["Int64", "Float64", "boolean"])
510def test_unique_labels_pandas_nullable(dtype):
511    """Checks that unique_labels work with pandas nullable dtypes.
512
513    Non-regression test for gh-25634.
514    """
515    pd = pytest.importorskip("pandas")
516
517    y_true = pd.Series([1, 0, 0, 1, 0, 1, 1, 0, 1], dtype=dtype)
518    y_predicted = pd.Series([0, 0, 1, 1, 0, 1, 1, 1, 1], dtype="int64")
519
520    labels = unique_labels(y_true, y_predicted)
521    assert_array_equal(labels, [0, 1])
522
523
524@pytest.mark.parametrize("csc_container", CSC_CONTAINERS)
525def test_class_distribution(csc_container):
526    y = np.array(
527        [
528            [1, 0, 0, 1],
529            [2, 2, 0, 1],
530            [1, 3, 0, 1],
531            [4, 2, 0, 1],
532            [2, 0, 0, 1],
533            [1, 3, 0, 1],
534        ]
535    )
536    # Define the sparse matrix with a mix of implicit and explicit zeros
537    data = np.array([1, 2, 1, 4, 2, 1, 0, 2, 3, 2, 3, 1, 1, 1, 1, 1, 1])
538    indices = np.array([0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 5, 0, 1, 2, 3, 4, 5])
539    indptr = np.array([0, 6, 11, 11, 17])
540    y_sp = csc_container((data, indices, indptr), shape=(6, 4))
541
542    classes, n_classes, class_prior = class_distribution(y)
543    classes_sp, n_classes_sp, class_prior_sp = class_distribution(y_sp)
544    classes_expected = [[1, 2, 4], [0, 2, 3], [0], [1]]
545    n_classes_expected = [3, 3, 1, 1]
546    class_prior_expected = [[3 / 6, 2 / 6, 1 / 6], [1 / 3, 1 / 3, 1 / 3], [1.0], [1.0]]
547
548    for k in range(y.shape[1]):
549        assert_array_almost_equal(classes[k], classes_expected[k])
550        assert_array_almost_equal(n_classes[k], n_classes_expected[k])
551        assert_array_almost_equal(class_prior[k], class_prior_expected[k])
552
553        assert_array_almost_equal(classes_sp[k], classes_expected[k])
554        assert_array_almost_equal(n_classes_sp[k], n_classes_expected[k])
555        assert_array_almost_equal(class_prior_sp[k], class_prior_expected[k])
556
557    # Test again with explicit sample weights
558    (classes, n_classes, class_prior) = class_distribution(
559        y, [1.0, 2.0, 1.0, 2.0, 1.0, 2.0]
560    )
561    (classes_sp, n_classes_sp, class_prior_sp) = class_distribution(
562        y, [1.0, 2.0, 1.0, 2.0, 1.0, 2.0]
563    )
564    class_prior_expected = [[4 / 9, 3 / 9, 2 / 9], [2 / 9, 4 / 9, 3 / 9], [1.0], [1.0]]
565
566    for k in range(y.shape[1]):
567        assert_array_almost_equal(classes[k], classes_expected[k])
568        assert_array_almost_equal(n_classes[k], n_classes_expected[k])
569        assert_array_almost_equal(class_prior[k], class_prior_expected[k])
570
571        assert_array_almost_equal(classes_sp[k], classes_expected[k])
572        assert_array_almost_equal(n_classes_sp[k], n_classes_expected[k])
573        assert_array_almost_equal(class_prior_sp[k], class_prior_expected[k])
574
575
576def test_safe_split_with_precomputed_kernel():
577    clf = SVC()
578    clfp = SVC(kernel="precomputed")
579
580    iris = datasets.load_iris()
581    X, y = iris.data, iris.target
582    K = np.dot(X, X.T)
583
584    cv = ShuffleSplit(test_size=0.25, random_state=0)
585    train, test = next(iter(cv.split(X)))
586
587    X_train, y_train = _safe_split(clf, X, y, train)
588    K_train, y_train2 = _safe_split(clfp, K, y, train)
589    assert_array_almost_equal(K_train, np.dot(X_train, X_train.T))
590    assert_array_almost_equal(y_train, y_train2)
591
592    X_test, y_test = _safe_split(clf, X, y, test, train)
593    K_test, y_test2 = _safe_split(clfp, K, y, test, train)
594    assert_array_almost_equal(K_test, np.dot(X_test, X_train.T))
595    assert_array_almost_equal(y_test, y_test2)
596
597
598def test_ovr_decision_function():
599    # test properties for ovr decision function
600
601    predictions = np.array([[0, 1, 1], [0, 1, 0], [0, 1, 1], [0, 1, 1]])
602
603    confidences = np.array(
604        [[-1e16, 0, -1e16], [1.0, 2.0, -3.0], [-5.0, 2.0, 5.0], [-0.5, 0.2, 0.5]]
605    )
606
607    n_classes = 3
608
609    dec_values = _ovr_decision_function(predictions, confidences, n_classes)
610
611    # check that the decision values are within 0.5 range of the votes
612    votes = np.array([[1, 0, 2], [1, 1, 1], [1, 0, 2], [1, 0, 2]])
613
614    assert_allclose(votes, dec_values, atol=0.5)
615
616    # check that the prediction are what we expect
617    # highest vote or highest confidence if there is a tie.
618    # for the second sample we have a tie (should be won by 1)
619    expected_prediction = np.array([2, 1, 2, 2])
620    assert_array_equal(np.argmax(dec_values, axis=1), expected_prediction)
621
622    # third and fourth sample have the same vote but third sample
623    # has higher confidence, this should reflect on the decision values
624    assert dec_values[2, 2] > dec_values[3, 2]
625
626    # assert subset invariance.
627    dec_values_one = [
628        _ovr_decision_function(
629            np.array([predictions[i]]), np.array([confidences[i]]), n_classes
630        )[0]
631        for i in range(4)
632    ]
633
634    assert_allclose(dec_values, dec_values_one, atol=1e-6)
635
636
637@pytest.mark.parametrize("input_type", ["list", "array"])
638def test_labels_in_bytes_format_error(input_type):
639    # check that we raise an error with bytes encoded labels
640    # non-regression test for:
641    # https://github.com/scikit-learn/scikit-learn/issues/16980
642    target = _convert_container([b"a", b"b"], input_type)
643    err_msg = "Support for labels represented as bytes is not supported"
644    with pytest.raises(TypeError, match=err_msg):
645        type_of_target(target)
646 
Aluode/PerceptionLabPortable · CoolFace