Aluode/PerceptionLabPortable
0
1"""Utilities for random sampling."""
2
3# Authors: The scikit-learn developers
4# SPDX-License-Identifier: BSD-3-Clause
5
6import array
7
8import numpy as np
9import scipy.sparse as sp
10
11from . import check_random_state
12from ._random import sample_without_replacement
13
14__all__ = ["sample_without_replacement"]
15
16
17def _random_choice_csc(n_samples, classes, class_probability=None, random_state=None):
18 """Generate a sparse random matrix given column class distributions
19
20 Parameters
21 ----------
22 n_samples : int,
23 Number of samples to draw in each column.
24
25 classes : list of size n_outputs of arrays of size (n_classes,)
26 List of classes for each column.
27
28 class_probability : list of size n_outputs of arrays of \
29 shape (n_classes,), default=None
30 Class distribution of each column. If None, uniform distribution is
31 assumed.
32
33 random_state : int, RandomState instance or None, default=None
34 Controls the randomness of the sampled classes.
35 See :term:`Glossary <random_state>`.
36
37 Returns
38 -------
39 random_matrix : sparse csc matrix of size (n_samples, n_outputs)
40
41 """
42 data = array.array("i")
43 indices = array.array("i")
44 indptr = array.array("i", [0])
45
46 for j in range(len(classes)):
47 classes[j] = np.asarray(classes[j])
48 if classes[j].dtype.kind != "i":
49 raise ValueError("class dtype %s is not supported" % classes[j].dtype)
50 classes[j] = classes[j].astype(np.int64, copy=False)
51
52 # use uniform distribution if no class_probability is given
53 if class_probability is None:
54 class_prob_j = np.empty(shape=classes[j].shape[0])
55 class_prob_j.fill(1 / classes[j].shape[0])
56 else:
57 class_prob_j = np.asarray(class_probability[j])
58
59 if not np.isclose(np.sum(class_prob_j), 1.0):
60 raise ValueError(
61 "Probability array at index {0} does not sum to one".format(j)
62 )
63
64 if class_prob_j.shape[0] != classes[j].shape[0]:
65 raise ValueError(
66 "classes[{0}] (length {1}) and "
67 "class_probability[{0}] (length {2}) have "
68 "different length.".format(
69 j, classes[j].shape[0], class_prob_j.shape[0]
70 )
71 )
72
73 # If 0 is not present in the classes insert it with a probability 0.0
74 if 0 not in classes[j]:
75 classes[j] = np.insert(classes[j], 0, 0)
76 class_prob_j = np.insert(class_prob_j, 0, 0.0)
77
78 # If there are nonzero classes choose randomly using class_probability
79 rng = check_random_state(random_state)
80 if classes[j].shape[0] > 1:
81 index_class_0 = np.flatnonzero(classes[j] == 0).item()
82 p_nonzero = 1 - class_prob_j[index_class_0]
83 nnz = int(n_samples * p_nonzero)
84 ind_sample = sample_without_replacement(
85 n_population=n_samples, n_samples=nnz, random_state=random_state
86 )
87 indices.extend(ind_sample)
88
89 # Normalize probabilities for the nonzero elements
90 classes_j_nonzero = classes[j] != 0
91 class_probability_nz = class_prob_j[classes_j_nonzero]
92 class_probability_nz_norm = class_probability_nz / np.sum(
93 class_probability_nz
94 )
95 classes_ind = np.searchsorted(
96 class_probability_nz_norm.cumsum(), rng.uniform(size=nnz)
97 )
98 data.extend(classes[j][classes_j_nonzero][classes_ind])
99 indptr.append(len(indices))
100
101 return sp.csc_matrix((data, indices, indptr), (n_samples, len(classes)), dtype=int)
102 