Aluode/PerceptionLabPortable
0
1# Authors: The scikit-learn developers
2# SPDX-License-Identifier: BSD-3-Clause
3
4import numpy as np
5
6from sklearn.utils._array_api import get_namespace
7
8
9def _attach_unique(y):
10 """Attach unique values of y to y and return the result.
11
12 The result is a view of y, and the metadata (unique) is not attached to y.
13 """
14 if not isinstance(y, np.ndarray):
15 return y
16 try:
17 # avoid recalculating unique in nested calls.
18 if "unique" in y.dtype.metadata:
19 return y
20 except (AttributeError, TypeError):
21 pass
22
23 unique = np.unique(y)
24 unique_dtype = np.dtype(y.dtype, metadata={"unique": unique})
25 return y.view(dtype=unique_dtype)
26
27
28def attach_unique(*ys, return_tuple=False):
29 """Attach unique values of ys to ys and return the results.
30
31 The result is a view of y, and the metadata (unique) is not attached to y.
32
33 IMPORTANT: The output of this function should NEVER be returned in functions.
34 This is to avoid this pattern:
35
36 .. code:: python
37
38 y = np.array([1, 2, 3])
39 y = attach_unique(y)
40 y[1] = -1
41 # now np.unique(y) will be different from cached_unique(y)
42
43 Parameters
44 ----------
45 *ys : sequence of array-like
46 Input data arrays.
47
48 return_tuple : bool, default=False
49 If True, always return a tuple even if there is only one array.
50
51 Returns
52 -------
53 ys : tuple of array-like or array-like
54 Input data with unique values attached.
55 """
56 res = tuple(_attach_unique(y) for y in ys)
57 if len(res) == 1 and not return_tuple:
58 return res[0]
59 return res
60
61
62def _cached_unique(y, xp=None):
63 """Return the unique values of y.
64
65 Use the cached values from dtype.metadata if present.
66
67 This function does NOT cache the values in y, i.e. it doesn't change y.
68
69 Call `attach_unique` to attach the unique values to y.
70 """
71 try:
72 if y.dtype.metadata is not None and "unique" in y.dtype.metadata:
73 return y.dtype.metadata["unique"]
74 except AttributeError:
75 # in case y is not a numpy array
76 pass
77 xp, _ = get_namespace(y, xp=xp)
78 return xp.unique_values(y)
79
80
81def cached_unique(*ys, xp=None):
82 """Return the unique values of ys.
83
84 Use the cached values from dtype.metadata if present.
85
86 This function does NOT cache the values in y, i.e. it doesn't change y.
87
88 Call `attach_unique` to attach the unique values to y.
89
90 Parameters
91 ----------
92 *ys : sequence of array-like
93 Input data arrays.
94
95 xp : module, default=None
96 Precomputed array namespace module. When passed, typically from a caller
97 that has already performed inspection of its own inputs, skips array
98 namespace inspection.
99
100 Returns
101 -------
102 res : tuple of array-like or array-like
103 Unique values of ys.
104 """
105 res = tuple(_cached_unique(y, xp=xp) for y in ys)
106 if len(res) == 1:
107 return res[0]
108 return res
109 