CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
test_random.py193 linesDownload Raw Back to tests
1import numpy as np
2import pytest
3import scipy.sparse as sp
4from numpy.testing import assert_array_almost_equal
5from scipy.special import comb
6
7from sklearn.utils._random import _our_rand_r_py
8from sklearn.utils.random import _random_choice_csc, sample_without_replacement
9
10
11###############################################################################
12# test custom sampling without replacement algorithm
13###############################################################################
14def test_invalid_sample_without_replacement_algorithm():
15    with pytest.raises(ValueError):
16        sample_without_replacement(5, 4, "unknown")
17
18
19def test_sample_without_replacement_algorithms():
20    methods = ("auto", "tracking_selection", "reservoir_sampling", "pool")
21
22    for m in methods:
23
24        def sample_without_replacement_method(
25            n_population, n_samples, random_state=None
26        ):
27            return sample_without_replacement(
28                n_population, n_samples, method=m, random_state=random_state
29            )
30
31        check_edge_case_of_sample_int(sample_without_replacement_method)
32        check_sample_int(sample_without_replacement_method)
33        check_sample_int_distribution(sample_without_replacement_method)
34
35
36def check_edge_case_of_sample_int(sample_without_replacement):
37    # n_population < n_sample
38    with pytest.raises(ValueError):
39        sample_without_replacement(0, 1)
40    with pytest.raises(ValueError):
41        sample_without_replacement(1, 2)
42
43    # n_population == n_samples
44    assert sample_without_replacement(0, 0).shape == (0,)
45
46    assert sample_without_replacement(1, 1).shape == (1,)
47
48    # n_population >= n_samples
49    assert sample_without_replacement(5, 0).shape == (0,)
50    assert sample_without_replacement(5, 1).shape == (1,)
51
52    # n_population < 0 or n_samples < 0
53    with pytest.raises(ValueError):
54        sample_without_replacement(-1, 5)
55    with pytest.raises(ValueError):
56        sample_without_replacement(5, -1)
57
58
59def check_sample_int(sample_without_replacement):
60    # This test is heavily inspired from test_random.py of python-core.
61    #
62    # For the entire allowable range of 0 <= k <= N, validate that
63    # the sample is of the correct length and contains only unique items
64    n_population = 100
65
66    for n_samples in range(n_population + 1):
67        s = sample_without_replacement(n_population, n_samples)
68        assert len(s) == n_samples
69        unique = np.unique(s)
70        assert np.size(unique) == n_samples
71        assert np.all(unique < n_population)
72
73    # test edge case n_population == n_samples == 0
74    assert np.size(sample_without_replacement(0, 0)) == 0
75
76
77def check_sample_int_distribution(sample_without_replacement):
78    # This test is heavily inspired from test_random.py of python-core.
79    #
80    # For the entire allowable range of 0 <= k <= N, validate that
81    # sample generates all possible permutations
82    n_population = 10
83
84    # a large number of trials prevents false negatives without slowing normal
85    # case
86    n_trials = 10000
87
88    for n_samples in range(n_population):
89        # Counting the number of combinations is not as good as counting the
90        # the number of permutations. However, it works with sampling algorithm
91        # that does not provide a random permutation of the subset of integer.
92        n_expected = comb(n_population, n_samples, exact=True)
93
94        output = {}
95        for i in range(n_trials):
96            output[frozenset(sample_without_replacement(n_population, n_samples))] = (
97                None
98            )
99
100            if len(output) == n_expected:
101                break
102        else:
103            raise AssertionError(
104                "number of combinations != number of expected (%s != %s)"
105                % (len(output), n_expected)
106            )
107
108
109def test_random_choice_csc(n_samples=10000, random_state=24):
110    # Explicit class probabilities
111    classes = [np.array([0, 1]), np.array([0, 1, 2])]
112    class_probabilities = [np.array([0.5, 0.5]), np.array([0.6, 0.1, 0.3])]
113
114    got = _random_choice_csc(n_samples, classes, class_probabilities, random_state)
115    assert sp.issparse(got)
116
117    for k in range(len(classes)):
118        p = np.bincount(got[:, [k]].toarray().ravel()) / float(n_samples)
119        assert_array_almost_equal(class_probabilities[k], p, decimal=1)
120
121    # Implicit class probabilities
122    classes = [[0, 1], [1, 2]]  # test for array-like support
123    class_probabilities = [np.array([0.5, 0.5]), np.array([0, 1 / 2, 1 / 2])]
124
125    got = _random_choice_csc(
126        n_samples=n_samples, classes=classes, random_state=random_state
127    )
128    assert sp.issparse(got)
129
130    for k in range(len(classes)):
131        p = np.bincount(got[:, [k]].toarray().ravel()) / float(n_samples)
132        assert_array_almost_equal(class_probabilities[k], p, decimal=1)
133
134    # Edge case probabilities 1.0 and 0.0
135    classes = [np.array([0, 1]), np.array([0, 1, 2])]
136    class_probabilities = [np.array([0.0, 1.0]), np.array([0.0, 1.0, 0.0])]
137
138    got = _random_choice_csc(n_samples, classes, class_probabilities, random_state)
139    assert sp.issparse(got)
140
141    for k in range(len(classes)):
142        p = (
143            np.bincount(
144                got[:, [k]].toarray().ravel(), minlength=len(class_probabilities[k])
145            )
146            / n_samples
147        )
148        assert_array_almost_equal(class_probabilities[k], p, decimal=1)
149
150    # One class target data
151    classes = [[1], [0]]  # test for array-like support
152    class_probabilities = [np.array([0.0, 1.0]), np.array([1.0])]
153
154    got = _random_choice_csc(
155        n_samples=n_samples, classes=classes, random_state=random_state
156    )
157    assert sp.issparse(got)
158
159    for k in range(len(classes)):
160        p = np.bincount(got[:, [k]].toarray().ravel()) / n_samples
161        assert_array_almost_equal(class_probabilities[k], p, decimal=1)
162
163
164def test_random_choice_csc_errors():
165    # the length of an array in classes and class_probabilities is mismatched
166    classes = [np.array([0, 1]), np.array([0, 1, 2, 3])]
167    class_probabilities = [np.array([0.5, 0.5]), np.array([0.6, 0.1, 0.3])]
168    with pytest.raises(ValueError):
169        _random_choice_csc(4, classes, class_probabilities, 1)
170
171    # the class dtype is not supported
172    classes = [np.array(["a", "1"]), np.array(["z", "1", "2"])]
173    class_probabilities = [np.array([0.5, 0.5]), np.array([0.6, 0.1, 0.3])]
174    with pytest.raises(ValueError):
175        _random_choice_csc(4, classes, class_probabilities, 1)
176
177    # the class dtype is not supported
178    classes = [np.array([4.2, 0.1]), np.array([0.1, 0.2, 9.4])]
179    class_probabilities = [np.array([0.5, 0.5]), np.array([0.6, 0.1, 0.3])]
180    with pytest.raises(ValueError):
181        _random_choice_csc(4, classes, class_probabilities, 1)
182
183    # Given probabilities don't sum to 1
184    classes = [np.array([0, 1]), np.array([0, 1, 2])]
185    class_probabilities = [np.array([0.5, 0.6]), np.array([0.6, 0.1, 0.3])]
186    with pytest.raises(ValueError):
187        _random_choice_csc(4, classes, class_probabilities, 1)
188
189
190def test_our_rand_r():
191    assert 131541053 == _our_rand_r_py(1273642419)
192    assert 270369 == _our_rand_r_py(0)
193 
Aluode/PerceptionLabPortable · CoolFace