ZhengyangZhang commited on
Commit
0853eac
·
verified ·
1 Parent(s): 5de2cea

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/pandas/_libs/__init__.py +27 -0
  2. lib/python3.12/site-packages/pandas/_libs/algos.pyi +416 -0
  3. lib/python3.12/site-packages/pandas/_libs/arrays.pyi +40 -0
  4. lib/python3.12/site-packages/pandas/_libs/byteswap.cpython-312-x86_64-linux-gnu.so +0 -0
  5. lib/python3.12/site-packages/pandas/_libs/byteswap.pyi +5 -0
  6. lib/python3.12/site-packages/pandas/_libs/groupby.pyi +216 -0
  7. lib/python3.12/site-packages/pandas/_libs/hashing.pyi +9 -0
  8. lib/python3.12/site-packages/pandas/_libs/hashtable.pyi +252 -0
  9. lib/python3.12/site-packages/pandas/_libs/index.pyi +100 -0
  10. lib/python3.12/site-packages/pandas/_libs/indexing.cpython-312-x86_64-linux-gnu.so +0 -0
  11. lib/python3.12/site-packages/pandas/_libs/indexing.pyi +17 -0
  12. lib/python3.12/site-packages/pandas/_libs/internals.pyi +94 -0
  13. lib/python3.12/site-packages/pandas/_libs/interval.pyi +174 -0
  14. lib/python3.12/site-packages/pandas/_libs/join.pyi +79 -0
  15. lib/python3.12/site-packages/pandas/_libs/json.cpython-312-x86_64-linux-gnu.so +0 -0
  16. lib/python3.12/site-packages/pandas/_libs/json.pyi +23 -0
  17. lib/python3.12/site-packages/pandas/_libs/lib.pyi +213 -0
  18. lib/python3.12/site-packages/pandas/_libs/missing.pyi +16 -0
  19. lib/python3.12/site-packages/pandas/_libs/ops.pyi +51 -0
  20. lib/python3.12/site-packages/pandas/_libs/ops_dispatch.cpython-312-x86_64-linux-gnu.so +0 -0
  21. lib/python3.12/site-packages/pandas/_libs/ops_dispatch.pyi +5 -0
  22. lib/python3.12/site-packages/pandas/_libs/pandas_datetime.cpython-312-x86_64-linux-gnu.so +0 -0
  23. lib/python3.12/site-packages/pandas/_libs/pandas_parser.cpython-312-x86_64-linux-gnu.so +0 -0
  24. lib/python3.12/site-packages/pandas/_libs/parsers.pyi +77 -0
  25. lib/python3.12/site-packages/pandas/_libs/properties.cpython-312-x86_64-linux-gnu.so +0 -0
  26. lib/python3.12/site-packages/pandas/_libs/properties.pyi +27 -0
  27. lib/python3.12/site-packages/pandas/_libs/reshape.pyi +16 -0
  28. lib/python3.12/site-packages/pandas/_libs/sas.pyi +7 -0
  29. lib/python3.12/site-packages/pandas/_libs/sparse.pyi +51 -0
  30. lib/python3.12/site-packages/pandas/_libs/testing.pyi +12 -0
  31. lib/python3.12/site-packages/pandas/_libs/tslib.pyi +37 -0
  32. lib/python3.12/site-packages/pandas/_libs/writers.pyi +20 -0
  33. lib/python3.12/site-packages/pandas/core/__init__.py +0 -0
  34. lib/python3.12/site-packages/pandas/core/accessor.py +340 -0
  35. lib/python3.12/site-packages/pandas/core/algorithms.py +1747 -0
  36. lib/python3.12/site-packages/pandas/core/api.py +140 -0
  37. lib/python3.12/site-packages/pandas/core/apply.py +2062 -0
  38. lib/python3.12/site-packages/pandas/core/array_algos/__init__.py +9 -0
  39. lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/__init__.cpython-312.pyc +0 -0
  40. lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/datetimelike_accumulations.cpython-312.pyc +0 -0
  41. lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/masked_accumulations.cpython-312.pyc +0 -0
  42. lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/masked_reductions.cpython-312.pyc +0 -0
  43. lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/putmask.cpython-312.pyc +0 -0
  44. lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/quantile.cpython-312.pyc +0 -0
  45. lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/replace.cpython-312.pyc +0 -0
  46. lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/take.cpython-312.pyc +0 -0
  47. lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/transforms.cpython-312.pyc +0 -0
  48. lib/python3.12/site-packages/pandas/core/array_algos/datetimelike_accumulations.py +67 -0
  49. lib/python3.12/site-packages/pandas/core/array_algos/masked_accumulations.py +90 -0
  50. lib/python3.12/site-packages/pandas/core/array_algos/masked_reductions.py +197 -0
lib/python3.12/site-packages/pandas/_libs/__init__.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __all__ = [
2
+ "NaT",
3
+ "NaTType",
4
+ "OutOfBoundsDatetime",
5
+ "Period",
6
+ "Timedelta",
7
+ "Timestamp",
8
+ "iNaT",
9
+ "Interval",
10
+ ]
11
+
12
+
13
+ # Below imports needs to happen first to ensure pandas top level
14
+ # module gets monkeypatched with the pandas_datetime_CAPI
15
+ # see pandas_datetime_exec in pd_datetime.c
16
+ import pandas._libs.pandas_parser # isort: skip # type: ignore[reportUnusedImport]
17
+ import pandas._libs.pandas_datetime # noqa: F401 # isort: skip # type: ignore[reportUnusedImport]
18
+ from pandas._libs.interval import Interval
19
+ from pandas._libs.tslibs import (
20
+ NaT,
21
+ NaTType,
22
+ OutOfBoundsDatetime,
23
+ Period,
24
+ Timedelta,
25
+ Timestamp,
26
+ iNaT,
27
+ )
lib/python3.12/site-packages/pandas/_libs/algos.pyi ADDED
@@ -0,0 +1,416 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+
3
+ import numpy as np
4
+
5
+ from pandas._typing import npt
6
+
7
+ class Infinity:
8
+ def __eq__(self, other) -> bool: ...
9
+ def __ne__(self, other) -> bool: ...
10
+ def __lt__(self, other) -> bool: ...
11
+ def __le__(self, other) -> bool: ...
12
+ def __gt__(self, other) -> bool: ...
13
+ def __ge__(self, other) -> bool: ...
14
+
15
+ class NegInfinity:
16
+ def __eq__(self, other) -> bool: ...
17
+ def __ne__(self, other) -> bool: ...
18
+ def __lt__(self, other) -> bool: ...
19
+ def __le__(self, other) -> bool: ...
20
+ def __gt__(self, other) -> bool: ...
21
+ def __ge__(self, other) -> bool: ...
22
+
23
+ def unique_deltas(
24
+ arr: np.ndarray, # const int64_t[:]
25
+ ) -> np.ndarray: ... # np.ndarray[np.int64, ndim=1]
26
+ def is_lexsorted(list_of_arrays: list[npt.NDArray[np.int64]]) -> bool: ...
27
+ def groupsort_indexer(
28
+ index: np.ndarray, # const int64_t[:]
29
+ ngroups: int,
30
+ ) -> tuple[
31
+ np.ndarray, # ndarray[int64_t, ndim=1]
32
+ np.ndarray, # ndarray[int64_t, ndim=1]
33
+ ]: ...
34
+ def kth_smallest(
35
+ arr: np.ndarray, # numeric[:]
36
+ k: int,
37
+ ) -> Any: ... # numeric
38
+
39
+ # ----------------------------------------------------------------------
40
+ # Pairwise correlation/covariance
41
+
42
+ def nancorr(
43
+ mat: npt.NDArray[np.float64], # const float64_t[:, :]
44
+ cov: bool = ...,
45
+ minp: int | None = ...,
46
+ ) -> npt.NDArray[np.float64]: ... # ndarray[float64_t, ndim=2]
47
+ def nancorr_spearman(
48
+ mat: npt.NDArray[np.float64], # ndarray[float64_t, ndim=2]
49
+ minp: int = ...,
50
+ ) -> npt.NDArray[np.float64]: ... # ndarray[float64_t, ndim=2]
51
+
52
+ # ----------------------------------------------------------------------
53
+
54
+ def validate_limit(nobs: int | None, limit=...) -> int: ...
55
+ def get_fill_indexer(
56
+ mask: npt.NDArray[np.bool_],
57
+ limit: int | None = None,
58
+ ) -> npt.NDArray[np.intp]: ...
59
+ def pad(
60
+ old: np.ndarray, # ndarray[numeric_object_t]
61
+ new: np.ndarray, # ndarray[numeric_object_t]
62
+ limit=...,
63
+ ) -> npt.NDArray[np.intp]: ... # np.ndarray[np.intp, ndim=1]
64
+ def pad_inplace(
65
+ values: np.ndarray, # numeric_object_t[:]
66
+ mask: np.ndarray, # uint8_t[:]
67
+ limit=...,
68
+ ) -> None: ...
69
+ def pad_2d_inplace(
70
+ values: np.ndarray, # numeric_object_t[:, :]
71
+ mask: np.ndarray, # const uint8_t[:, :]
72
+ limit=...,
73
+ ) -> None: ...
74
+ def backfill(
75
+ old: np.ndarray, # ndarray[numeric_object_t]
76
+ new: np.ndarray, # ndarray[numeric_object_t]
77
+ limit=...,
78
+ ) -> npt.NDArray[np.intp]: ... # np.ndarray[np.intp, ndim=1]
79
+ def backfill_inplace(
80
+ values: np.ndarray, # numeric_object_t[:]
81
+ mask: np.ndarray, # uint8_t[:]
82
+ limit=...,
83
+ ) -> None: ...
84
+ def backfill_2d_inplace(
85
+ values: np.ndarray, # numeric_object_t[:, :]
86
+ mask: np.ndarray, # const uint8_t[:, :]
87
+ limit=...,
88
+ ) -> None: ...
89
+ def is_monotonic(
90
+ arr: np.ndarray, # ndarray[numeric_object_t, ndim=1]
91
+ timelike: bool,
92
+ ) -> tuple[bool, bool, bool]: ...
93
+
94
+ # ----------------------------------------------------------------------
95
+ # rank_1d, rank_2d
96
+ # ----------------------------------------------------------------------
97
+
98
+ def rank_1d(
99
+ values: np.ndarray, # ndarray[numeric_object_t, ndim=1]
100
+ labels: np.ndarray | None = ..., # const int64_t[:]=None
101
+ is_datetimelike: bool = ...,
102
+ ties_method=...,
103
+ ascending: bool = ...,
104
+ pct: bool = ...,
105
+ na_option=...,
106
+ mask: npt.NDArray[np.bool_] | None = ...,
107
+ ) -> np.ndarray: ... # np.ndarray[float64_t, ndim=1]
108
+ def rank_2d(
109
+ in_arr: np.ndarray, # ndarray[numeric_object_t, ndim=2]
110
+ axis: int = ...,
111
+ is_datetimelike: bool = ...,
112
+ ties_method=...,
113
+ ascending: bool = ...,
114
+ na_option=...,
115
+ pct: bool = ...,
116
+ ) -> np.ndarray: ... # np.ndarray[float64_t, ndim=1]
117
+ def diff_2d(
118
+ arr: np.ndarray, # ndarray[diff_t, ndim=2]
119
+ out: np.ndarray, # ndarray[out_t, ndim=2]
120
+ periods: int,
121
+ axis: int,
122
+ datetimelike: bool = ...,
123
+ ) -> None: ...
124
+ def ensure_platform_int(arr: object) -> npt.NDArray[np.intp]: ...
125
+ def ensure_object(arr: object) -> npt.NDArray[np.object_]: ...
126
+ def ensure_float64(arr: object) -> npt.NDArray[np.float64]: ...
127
+ def ensure_int8(arr: object) -> npt.NDArray[np.int8]: ...
128
+ def ensure_int16(arr: object) -> npt.NDArray[np.int16]: ...
129
+ def ensure_int32(arr: object) -> npt.NDArray[np.int32]: ...
130
+ def ensure_int64(arr: object) -> npt.NDArray[np.int64]: ...
131
+ def ensure_uint64(arr: object) -> npt.NDArray[np.uint64]: ...
132
+ def take_1d_int8_int8(
133
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
134
+ ) -> None: ...
135
+ def take_1d_int8_int32(
136
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
137
+ ) -> None: ...
138
+ def take_1d_int8_int64(
139
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
140
+ ) -> None: ...
141
+ def take_1d_int8_float64(
142
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
143
+ ) -> None: ...
144
+ def take_1d_int16_int16(
145
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
146
+ ) -> None: ...
147
+ def take_1d_int16_int32(
148
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
149
+ ) -> None: ...
150
+ def take_1d_int16_int64(
151
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
152
+ ) -> None: ...
153
+ def take_1d_int16_float64(
154
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
155
+ ) -> None: ...
156
+ def take_1d_int32_int32(
157
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
158
+ ) -> None: ...
159
+ def take_1d_int32_int64(
160
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
161
+ ) -> None: ...
162
+ def take_1d_int32_float64(
163
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
164
+ ) -> None: ...
165
+ def take_1d_int64_int64(
166
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
167
+ ) -> None: ...
168
+ def take_1d_int64_float64(
169
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
170
+ ) -> None: ...
171
+ def take_1d_float32_float32(
172
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
173
+ ) -> None: ...
174
+ def take_1d_float32_float64(
175
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
176
+ ) -> None: ...
177
+ def take_1d_float64_float64(
178
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
179
+ ) -> None: ...
180
+ def take_1d_object_object(
181
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
182
+ ) -> None: ...
183
+ def take_1d_bool_bool(
184
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
185
+ ) -> None: ...
186
+ def take_1d_bool_object(
187
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
188
+ ) -> None: ...
189
+ def take_2d_axis0_int8_int8(
190
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
191
+ ) -> None: ...
192
+ def take_2d_axis0_int8_int32(
193
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
194
+ ) -> None: ...
195
+ def take_2d_axis0_int8_int64(
196
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
197
+ ) -> None: ...
198
+ def take_2d_axis0_int8_float64(
199
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
200
+ ) -> None: ...
201
+ def take_2d_axis0_int16_int16(
202
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
203
+ ) -> None: ...
204
+ def take_2d_axis0_int16_int32(
205
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
206
+ ) -> None: ...
207
+ def take_2d_axis0_int16_int64(
208
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
209
+ ) -> None: ...
210
+ def take_2d_axis0_int16_float64(
211
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
212
+ ) -> None: ...
213
+ def take_2d_axis0_int32_int32(
214
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
215
+ ) -> None: ...
216
+ def take_2d_axis0_int32_int64(
217
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
218
+ ) -> None: ...
219
+ def take_2d_axis0_int32_float64(
220
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
221
+ ) -> None: ...
222
+ def take_2d_axis0_int64_int64(
223
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
224
+ ) -> None: ...
225
+ def take_2d_axis0_int64_float64(
226
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
227
+ ) -> None: ...
228
+ def take_2d_axis0_float32_float32(
229
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
230
+ ) -> None: ...
231
+ def take_2d_axis0_float32_float64(
232
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
233
+ ) -> None: ...
234
+ def take_2d_axis0_float64_float64(
235
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
236
+ ) -> None: ...
237
+ def take_2d_axis0_object_object(
238
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
239
+ ) -> None: ...
240
+ def take_2d_axis0_bool_bool(
241
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
242
+ ) -> None: ...
243
+ def take_2d_axis0_bool_object(
244
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
245
+ ) -> None: ...
246
+ def take_2d_axis1_int8_int8(
247
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
248
+ ) -> None: ...
249
+ def take_2d_axis1_int8_int32(
250
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
251
+ ) -> None: ...
252
+ def take_2d_axis1_int8_int64(
253
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
254
+ ) -> None: ...
255
+ def take_2d_axis1_int8_float64(
256
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
257
+ ) -> None: ...
258
+ def take_2d_axis1_int16_int16(
259
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
260
+ ) -> None: ...
261
+ def take_2d_axis1_int16_int32(
262
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
263
+ ) -> None: ...
264
+ def take_2d_axis1_int16_int64(
265
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
266
+ ) -> None: ...
267
+ def take_2d_axis1_int16_float64(
268
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
269
+ ) -> None: ...
270
+ def take_2d_axis1_int32_int32(
271
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
272
+ ) -> None: ...
273
+ def take_2d_axis1_int32_int64(
274
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
275
+ ) -> None: ...
276
+ def take_2d_axis1_int32_float64(
277
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
278
+ ) -> None: ...
279
+ def take_2d_axis1_int64_int64(
280
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
281
+ ) -> None: ...
282
+ def take_2d_axis1_int64_float64(
283
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
284
+ ) -> None: ...
285
+ def take_2d_axis1_float32_float32(
286
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
287
+ ) -> None: ...
288
+ def take_2d_axis1_float32_float64(
289
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
290
+ ) -> None: ...
291
+ def take_2d_axis1_float64_float64(
292
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
293
+ ) -> None: ...
294
+ def take_2d_axis1_object_object(
295
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
296
+ ) -> None: ...
297
+ def take_2d_axis1_bool_bool(
298
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
299
+ ) -> None: ...
300
+ def take_2d_axis1_bool_object(
301
+ values: np.ndarray, indexer: npt.NDArray[np.intp], out: np.ndarray, fill_value=...
302
+ ) -> None: ...
303
+ def take_2d_multi_int8_int8(
304
+ values: np.ndarray,
305
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
306
+ out: np.ndarray,
307
+ fill_value=...,
308
+ ) -> None: ...
309
+ def take_2d_multi_int8_int32(
310
+ values: np.ndarray,
311
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
312
+ out: np.ndarray,
313
+ fill_value=...,
314
+ ) -> None: ...
315
+ def take_2d_multi_int8_int64(
316
+ values: np.ndarray,
317
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
318
+ out: np.ndarray,
319
+ fill_value=...,
320
+ ) -> None: ...
321
+ def take_2d_multi_int8_float64(
322
+ values: np.ndarray,
323
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
324
+ out: np.ndarray,
325
+ fill_value=...,
326
+ ) -> None: ...
327
+ def take_2d_multi_int16_int16(
328
+ values: np.ndarray,
329
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
330
+ out: np.ndarray,
331
+ fill_value=...,
332
+ ) -> None: ...
333
+ def take_2d_multi_int16_int32(
334
+ values: np.ndarray,
335
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
336
+ out: np.ndarray,
337
+ fill_value=...,
338
+ ) -> None: ...
339
+ def take_2d_multi_int16_int64(
340
+ values: np.ndarray,
341
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
342
+ out: np.ndarray,
343
+ fill_value=...,
344
+ ) -> None: ...
345
+ def take_2d_multi_int16_float64(
346
+ values: np.ndarray,
347
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
348
+ out: np.ndarray,
349
+ fill_value=...,
350
+ ) -> None: ...
351
+ def take_2d_multi_int32_int32(
352
+ values: np.ndarray,
353
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
354
+ out: np.ndarray,
355
+ fill_value=...,
356
+ ) -> None: ...
357
+ def take_2d_multi_int32_int64(
358
+ values: np.ndarray,
359
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
360
+ out: np.ndarray,
361
+ fill_value=...,
362
+ ) -> None: ...
363
+ def take_2d_multi_int32_float64(
364
+ values: np.ndarray,
365
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
366
+ out: np.ndarray,
367
+ fill_value=...,
368
+ ) -> None: ...
369
+ def take_2d_multi_int64_float64(
370
+ values: np.ndarray,
371
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
372
+ out: np.ndarray,
373
+ fill_value=...,
374
+ ) -> None: ...
375
+ def take_2d_multi_float32_float32(
376
+ values: np.ndarray,
377
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
378
+ out: np.ndarray,
379
+ fill_value=...,
380
+ ) -> None: ...
381
+ def take_2d_multi_float32_float64(
382
+ values: np.ndarray,
383
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
384
+ out: np.ndarray,
385
+ fill_value=...,
386
+ ) -> None: ...
387
+ def take_2d_multi_float64_float64(
388
+ values: np.ndarray,
389
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
390
+ out: np.ndarray,
391
+ fill_value=...,
392
+ ) -> None: ...
393
+ def take_2d_multi_object_object(
394
+ values: np.ndarray,
395
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
396
+ out: np.ndarray,
397
+ fill_value=...,
398
+ ) -> None: ...
399
+ def take_2d_multi_bool_bool(
400
+ values: np.ndarray,
401
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
402
+ out: np.ndarray,
403
+ fill_value=...,
404
+ ) -> None: ...
405
+ def take_2d_multi_bool_object(
406
+ values: np.ndarray,
407
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
408
+ out: np.ndarray,
409
+ fill_value=...,
410
+ ) -> None: ...
411
+ def take_2d_multi_int64_int64(
412
+ values: np.ndarray,
413
+ indexer: tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]],
414
+ out: np.ndarray,
415
+ fill_value=...,
416
+ ) -> None: ...
lib/python3.12/site-packages/pandas/_libs/arrays.pyi ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Sequence
2
+
3
+ import numpy as np
4
+
5
+ from pandas._typing import (
6
+ AxisInt,
7
+ DtypeObj,
8
+ Self,
9
+ Shape,
10
+ )
11
+
12
+ class NDArrayBacked:
13
+ _dtype: DtypeObj
14
+ _ndarray: np.ndarray
15
+ def __init__(self, values: np.ndarray, dtype: DtypeObj) -> None: ...
16
+ @classmethod
17
+ def _simple_new(cls, values: np.ndarray, dtype: DtypeObj): ...
18
+ def _from_backing_data(self, values: np.ndarray): ...
19
+ def __setstate__(self, state): ...
20
+ def __len__(self) -> int: ...
21
+ @property
22
+ def shape(self) -> Shape: ...
23
+ @property
24
+ def ndim(self) -> int: ...
25
+ @property
26
+ def size(self) -> int: ...
27
+ @property
28
+ def nbytes(self) -> int: ...
29
+ def copy(self, order=...): ...
30
+ def delete(self, loc, axis=...): ...
31
+ def swapaxes(self, axis1, axis2): ...
32
+ def repeat(self, repeats: int | Sequence[int], axis: int | None = ...): ...
33
+ def reshape(self, *args, **kwargs): ...
34
+ def ravel(self, order=...): ...
35
+ @property
36
+ def T(self): ...
37
+ @classmethod
38
+ def _concat_same_type(
39
+ cls, to_concat: Sequence[Self], axis: AxisInt = ...
40
+ ) -> Self: ...
lib/python3.12/site-packages/pandas/_libs/byteswap.cpython-312-x86_64-linux-gnu.so ADDED
Binary file (61.7 kB). View file
 
lib/python3.12/site-packages/pandas/_libs/byteswap.pyi ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ def read_float_with_byteswap(data: bytes, offset: int, byteswap: bool) -> float: ...
2
+ def read_double_with_byteswap(data: bytes, offset: int, byteswap: bool) -> float: ...
3
+ def read_uint16_with_byteswap(data: bytes, offset: int, byteswap: bool) -> int: ...
4
+ def read_uint32_with_byteswap(data: bytes, offset: int, byteswap: bool) -> int: ...
5
+ def read_uint64_with_byteswap(data: bytes, offset: int, byteswap: bool) -> int: ...
lib/python3.12/site-packages/pandas/_libs/groupby.pyi ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Literal
2
+
3
+ import numpy as np
4
+
5
+ from pandas._typing import npt
6
+
7
+ def group_median_float64(
8
+ out: np.ndarray, # ndarray[float64_t, ndim=2]
9
+ counts: npt.NDArray[np.int64],
10
+ values: np.ndarray, # ndarray[float64_t, ndim=2]
11
+ labels: npt.NDArray[np.int64],
12
+ min_count: int = ..., # Py_ssize_t
13
+ mask: np.ndarray | None = ...,
14
+ result_mask: np.ndarray | None = ...,
15
+ ) -> None: ...
16
+ def group_cumprod(
17
+ out: np.ndarray, # float64_t[:, ::1]
18
+ values: np.ndarray, # const float64_t[:, :]
19
+ labels: np.ndarray, # const int64_t[:]
20
+ ngroups: int,
21
+ is_datetimelike: bool,
22
+ skipna: bool = ...,
23
+ mask: np.ndarray | None = ...,
24
+ result_mask: np.ndarray | None = ...,
25
+ ) -> None: ...
26
+ def group_cumsum(
27
+ out: np.ndarray, # int64float_t[:, ::1]
28
+ values: np.ndarray, # ndarray[int64float_t, ndim=2]
29
+ labels: np.ndarray, # const int64_t[:]
30
+ ngroups: int,
31
+ is_datetimelike: bool,
32
+ skipna: bool = ...,
33
+ mask: np.ndarray | None = ...,
34
+ result_mask: np.ndarray | None = ...,
35
+ ) -> None: ...
36
+ def group_shift_indexer(
37
+ out: np.ndarray, # int64_t[::1]
38
+ labels: np.ndarray, # const int64_t[:]
39
+ ngroups: int,
40
+ periods: int,
41
+ ) -> None: ...
42
+ def group_fillna_indexer(
43
+ out: np.ndarray, # ndarray[intp_t]
44
+ labels: np.ndarray, # ndarray[int64_t]
45
+ sorted_labels: npt.NDArray[np.intp],
46
+ mask: npt.NDArray[np.uint8],
47
+ limit: int, # int64_t
48
+ dropna: bool,
49
+ ) -> None: ...
50
+ def group_any_all(
51
+ out: np.ndarray, # uint8_t[::1]
52
+ values: np.ndarray, # const uint8_t[::1]
53
+ labels: np.ndarray, # const int64_t[:]
54
+ mask: np.ndarray, # const uint8_t[::1]
55
+ val_test: Literal["any", "all"],
56
+ skipna: bool,
57
+ result_mask: np.ndarray | None,
58
+ ) -> None: ...
59
+ def group_sum(
60
+ out: np.ndarray, # complexfloatingintuint_t[:, ::1]
61
+ counts: np.ndarray, # int64_t[::1]
62
+ values: np.ndarray, # ndarray[complexfloatingintuint_t, ndim=2]
63
+ labels: np.ndarray, # const intp_t[:]
64
+ mask: np.ndarray | None,
65
+ result_mask: np.ndarray | None = ...,
66
+ min_count: int = ...,
67
+ is_datetimelike: bool = ...,
68
+ ) -> None: ...
69
+ def group_prod(
70
+ out: np.ndarray, # int64float_t[:, ::1]
71
+ counts: np.ndarray, # int64_t[::1]
72
+ values: np.ndarray, # ndarray[int64float_t, ndim=2]
73
+ labels: np.ndarray, # const intp_t[:]
74
+ mask: np.ndarray | None,
75
+ result_mask: np.ndarray | None = ...,
76
+ min_count: int = ...,
77
+ ) -> None: ...
78
+ def group_var(
79
+ out: np.ndarray, # floating[:, ::1]
80
+ counts: np.ndarray, # int64_t[::1]
81
+ values: np.ndarray, # ndarray[floating, ndim=2]
82
+ labels: np.ndarray, # const intp_t[:]
83
+ min_count: int = ..., # Py_ssize_t
84
+ ddof: int = ..., # int64_t
85
+ mask: np.ndarray | None = ...,
86
+ result_mask: np.ndarray | None = ...,
87
+ is_datetimelike: bool = ...,
88
+ name: str = ...,
89
+ ) -> None: ...
90
+ def group_skew(
91
+ out: np.ndarray, # float64_t[:, ::1]
92
+ counts: np.ndarray, # int64_t[::1]
93
+ values: np.ndarray, # ndarray[float64_T, ndim=2]
94
+ labels: np.ndarray, # const intp_t[::1]
95
+ mask: np.ndarray | None = ...,
96
+ result_mask: np.ndarray | None = ...,
97
+ skipna: bool = ...,
98
+ ) -> None: ...
99
+ def group_mean(
100
+ out: np.ndarray, # floating[:, ::1]
101
+ counts: np.ndarray, # int64_t[::1]
102
+ values: np.ndarray, # ndarray[floating, ndim=2]
103
+ labels: np.ndarray, # const intp_t[:]
104
+ min_count: int = ..., # Py_ssize_t
105
+ is_datetimelike: bool = ..., # bint
106
+ mask: np.ndarray | None = ...,
107
+ result_mask: np.ndarray | None = ...,
108
+ ) -> None: ...
109
+ def group_ohlc(
110
+ out: np.ndarray, # floatingintuint_t[:, ::1]
111
+ counts: np.ndarray, # int64_t[::1]
112
+ values: np.ndarray, # ndarray[floatingintuint_t, ndim=2]
113
+ labels: np.ndarray, # const intp_t[:]
114
+ min_count: int = ...,
115
+ mask: np.ndarray | None = ...,
116
+ result_mask: np.ndarray | None = ...,
117
+ ) -> None: ...
118
+ def group_quantile(
119
+ out: npt.NDArray[np.float64],
120
+ values: np.ndarray, # ndarray[numeric, ndim=1]
121
+ labels: npt.NDArray[np.intp],
122
+ mask: npt.NDArray[np.uint8],
123
+ qs: npt.NDArray[np.float64], # const
124
+ starts: npt.NDArray[np.int64],
125
+ ends: npt.NDArray[np.int64],
126
+ interpolation: Literal["linear", "lower", "higher", "nearest", "midpoint"],
127
+ result_mask: np.ndarray | None,
128
+ is_datetimelike: bool,
129
+ ) -> None: ...
130
+ def group_last(
131
+ out: np.ndarray, # rank_t[:, ::1]
132
+ counts: np.ndarray, # int64_t[::1]
133
+ values: np.ndarray, # ndarray[rank_t, ndim=2]
134
+ labels: np.ndarray, # const int64_t[:]
135
+ mask: npt.NDArray[np.bool_] | None,
136
+ result_mask: npt.NDArray[np.bool_] | None = ...,
137
+ min_count: int = ..., # Py_ssize_t
138
+ is_datetimelike: bool = ...,
139
+ skipna: bool = ...,
140
+ ) -> None: ...
141
+ def group_nth(
142
+ out: np.ndarray, # rank_t[:, ::1]
143
+ counts: np.ndarray, # int64_t[::1]
144
+ values: np.ndarray, # ndarray[rank_t, ndim=2]
145
+ labels: np.ndarray, # const int64_t[:]
146
+ mask: npt.NDArray[np.bool_] | None,
147
+ result_mask: npt.NDArray[np.bool_] | None = ...,
148
+ min_count: int = ..., # int64_t
149
+ rank: int = ..., # int64_t
150
+ is_datetimelike: bool = ...,
151
+ skipna: bool = ...,
152
+ ) -> None: ...
153
+ def group_rank(
154
+ out: np.ndarray, # float64_t[:, ::1]
155
+ values: np.ndarray, # ndarray[rank_t, ndim=2]
156
+ labels: np.ndarray, # const int64_t[:]
157
+ ngroups: int,
158
+ is_datetimelike: bool,
159
+ ties_method: Literal["average", "min", "max", "first", "dense"] = ...,
160
+ ascending: bool = ...,
161
+ pct: bool = ...,
162
+ na_option: Literal["keep", "top", "bottom"] = ...,
163
+ mask: npt.NDArray[np.bool_] | None = ...,
164
+ ) -> None: ...
165
+ def group_max(
166
+ out: np.ndarray, # groupby_t[:, ::1]
167
+ counts: np.ndarray, # int64_t[::1]
168
+ values: np.ndarray, # ndarray[groupby_t, ndim=2]
169
+ labels: np.ndarray, # const int64_t[:]
170
+ min_count: int = ...,
171
+ is_datetimelike: bool = ...,
172
+ mask: np.ndarray | None = ...,
173
+ result_mask: np.ndarray | None = ...,
174
+ ) -> None: ...
175
+ def group_min(
176
+ out: np.ndarray, # groupby_t[:, ::1]
177
+ counts: np.ndarray, # int64_t[::1]
178
+ values: np.ndarray, # ndarray[groupby_t, ndim=2]
179
+ labels: np.ndarray, # const int64_t[:]
180
+ min_count: int = ...,
181
+ is_datetimelike: bool = ...,
182
+ mask: np.ndarray | None = ...,
183
+ result_mask: np.ndarray | None = ...,
184
+ ) -> None: ...
185
+ def group_idxmin_idxmax(
186
+ out: npt.NDArray[np.intp],
187
+ counts: npt.NDArray[np.int64],
188
+ values: np.ndarray, # ndarray[groupby_t, ndim=2]
189
+ labels: npt.NDArray[np.intp],
190
+ min_count: int = ...,
191
+ is_datetimelike: bool = ...,
192
+ mask: np.ndarray | None = ...,
193
+ name: str = ...,
194
+ skipna: bool = ...,
195
+ result_mask: np.ndarray | None = ...,
196
+ ) -> None: ...
197
+ def group_cummin(
198
+ out: np.ndarray, # groupby_t[:, ::1]
199
+ values: np.ndarray, # ndarray[groupby_t, ndim=2]
200
+ labels: np.ndarray, # const int64_t[:]
201
+ ngroups: int,
202
+ is_datetimelike: bool,
203
+ mask: np.ndarray | None = ...,
204
+ result_mask: np.ndarray | None = ...,
205
+ skipna: bool = ...,
206
+ ) -> None: ...
207
+ def group_cummax(
208
+ out: np.ndarray, # groupby_t[:, ::1]
209
+ values: np.ndarray, # ndarray[groupby_t, ndim=2]
210
+ labels: np.ndarray, # const int64_t[:]
211
+ ngroups: int,
212
+ is_datetimelike: bool,
213
+ mask: np.ndarray | None = ...,
214
+ result_mask: np.ndarray | None = ...,
215
+ skipna: bool = ...,
216
+ ) -> None: ...
lib/python3.12/site-packages/pandas/_libs/hashing.pyi ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ from pandas._typing import npt
4
+
5
+ def hash_object_array(
6
+ arr: npt.NDArray[np.object_],
7
+ key: str,
8
+ encoding: str = ...,
9
+ ) -> npt.NDArray[np.uint64]: ...
lib/python3.12/site-packages/pandas/_libs/hashtable.pyi ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import (
2
+ Any,
3
+ Hashable,
4
+ Literal,
5
+ )
6
+
7
+ import numpy as np
8
+
9
+ from pandas._typing import npt
10
+
11
+ def unique_label_indices(
12
+ labels: np.ndarray, # const int64_t[:]
13
+ ) -> np.ndarray: ...
14
+
15
+ class Factorizer:
16
+ count: int
17
+ uniques: Any
18
+ def __init__(self, size_hint: int) -> None: ...
19
+ def get_count(self) -> int: ...
20
+ def factorize(
21
+ self,
22
+ values: np.ndarray,
23
+ na_sentinel=...,
24
+ na_value=...,
25
+ mask=...,
26
+ ) -> npt.NDArray[np.intp]: ...
27
+
28
+ class ObjectFactorizer(Factorizer):
29
+ table: PyObjectHashTable
30
+ uniques: ObjectVector
31
+
32
+ class Int64Factorizer(Factorizer):
33
+ table: Int64HashTable
34
+ uniques: Int64Vector
35
+
36
+ class UInt64Factorizer(Factorizer):
37
+ table: UInt64HashTable
38
+ uniques: UInt64Vector
39
+
40
+ class Int32Factorizer(Factorizer):
41
+ table: Int32HashTable
42
+ uniques: Int32Vector
43
+
44
+ class UInt32Factorizer(Factorizer):
45
+ table: UInt32HashTable
46
+ uniques: UInt32Vector
47
+
48
+ class Int16Factorizer(Factorizer):
49
+ table: Int16HashTable
50
+ uniques: Int16Vector
51
+
52
+ class UInt16Factorizer(Factorizer):
53
+ table: UInt16HashTable
54
+ uniques: UInt16Vector
55
+
56
+ class Int8Factorizer(Factorizer):
57
+ table: Int8HashTable
58
+ uniques: Int8Vector
59
+
60
+ class UInt8Factorizer(Factorizer):
61
+ table: UInt8HashTable
62
+ uniques: UInt8Vector
63
+
64
+ class Float64Factorizer(Factorizer):
65
+ table: Float64HashTable
66
+ uniques: Float64Vector
67
+
68
+ class Float32Factorizer(Factorizer):
69
+ table: Float32HashTable
70
+ uniques: Float32Vector
71
+
72
+ class Complex64Factorizer(Factorizer):
73
+ table: Complex64HashTable
74
+ uniques: Complex64Vector
75
+
76
+ class Complex128Factorizer(Factorizer):
77
+ table: Complex128HashTable
78
+ uniques: Complex128Vector
79
+
80
+ class Int64Vector:
81
+ def __init__(self, *args) -> None: ...
82
+ def __len__(self) -> int: ...
83
+ def to_array(self) -> npt.NDArray[np.int64]: ...
84
+
85
+ class Int32Vector:
86
+ def __init__(self, *args) -> None: ...
87
+ def __len__(self) -> int: ...
88
+ def to_array(self) -> npt.NDArray[np.int32]: ...
89
+
90
+ class Int16Vector:
91
+ def __init__(self, *args) -> None: ...
92
+ def __len__(self) -> int: ...
93
+ def to_array(self) -> npt.NDArray[np.int16]: ...
94
+
95
+ class Int8Vector:
96
+ def __init__(self, *args) -> None: ...
97
+ def __len__(self) -> int: ...
98
+ def to_array(self) -> npt.NDArray[np.int8]: ...
99
+
100
+ class UInt64Vector:
101
+ def __init__(self, *args) -> None: ...
102
+ def __len__(self) -> int: ...
103
+ def to_array(self) -> npt.NDArray[np.uint64]: ...
104
+
105
+ class UInt32Vector:
106
+ def __init__(self, *args) -> None: ...
107
+ def __len__(self) -> int: ...
108
+ def to_array(self) -> npt.NDArray[np.uint32]: ...
109
+
110
+ class UInt16Vector:
111
+ def __init__(self, *args) -> None: ...
112
+ def __len__(self) -> int: ...
113
+ def to_array(self) -> npt.NDArray[np.uint16]: ...
114
+
115
+ class UInt8Vector:
116
+ def __init__(self, *args) -> None: ...
117
+ def __len__(self) -> int: ...
118
+ def to_array(self) -> npt.NDArray[np.uint8]: ...
119
+
120
+ class Float64Vector:
121
+ def __init__(self, *args) -> None: ...
122
+ def __len__(self) -> int: ...
123
+ def to_array(self) -> npt.NDArray[np.float64]: ...
124
+
125
+ class Float32Vector:
126
+ def __init__(self, *args) -> None: ...
127
+ def __len__(self) -> int: ...
128
+ def to_array(self) -> npt.NDArray[np.float32]: ...
129
+
130
+ class Complex128Vector:
131
+ def __init__(self, *args) -> None: ...
132
+ def __len__(self) -> int: ...
133
+ def to_array(self) -> npt.NDArray[np.complex128]: ...
134
+
135
+ class Complex64Vector:
136
+ def __init__(self, *args) -> None: ...
137
+ def __len__(self) -> int: ...
138
+ def to_array(self) -> npt.NDArray[np.complex64]: ...
139
+
140
+ class StringVector:
141
+ def __init__(self, *args) -> None: ...
142
+ def __len__(self) -> int: ...
143
+ def to_array(self) -> npt.NDArray[np.object_]: ...
144
+
145
+ class ObjectVector:
146
+ def __init__(self, *args) -> None: ...
147
+ def __len__(self) -> int: ...
148
+ def to_array(self) -> npt.NDArray[np.object_]: ...
149
+
150
+ class HashTable:
151
+ # NB: The base HashTable class does _not_ actually have these methods;
152
+ # we are putting them here for the sake of mypy to avoid
153
+ # reproducing them in each subclass below.
154
+ def __init__(self, size_hint: int = ..., uses_mask: bool = ...) -> None: ...
155
+ def __len__(self) -> int: ...
156
+ def __contains__(self, key: Hashable) -> bool: ...
157
+ def sizeof(self, deep: bool = ...) -> int: ...
158
+ def get_state(self) -> dict[str, int]: ...
159
+ # TODO: `val/key` type is subclass-specific
160
+ def get_item(self, val): ... # TODO: return type?
161
+ def set_item(self, key, val) -> None: ...
162
+ def get_na(self): ... # TODO: return type?
163
+ def set_na(self, val) -> None: ...
164
+ def map_locations(
165
+ self,
166
+ values: np.ndarray, # np.ndarray[subclass-specific]
167
+ mask: npt.NDArray[np.bool_] | None = ...,
168
+ ) -> None: ...
169
+ def lookup(
170
+ self,
171
+ values: np.ndarray, # np.ndarray[subclass-specific]
172
+ mask: npt.NDArray[np.bool_] | None = ...,
173
+ ) -> npt.NDArray[np.intp]: ...
174
+ def get_labels(
175
+ self,
176
+ values: np.ndarray, # np.ndarray[subclass-specific]
177
+ uniques, # SubclassTypeVector
178
+ count_prior: int = ...,
179
+ na_sentinel: int = ...,
180
+ na_value: object = ...,
181
+ mask=...,
182
+ ) -> npt.NDArray[np.intp]: ...
183
+ def unique(
184
+ self,
185
+ values: np.ndarray, # np.ndarray[subclass-specific]
186
+ return_inverse: bool = ...,
187
+ mask=...,
188
+ ) -> (
189
+ tuple[
190
+ np.ndarray, # np.ndarray[subclass-specific]
191
+ npt.NDArray[np.intp],
192
+ ]
193
+ | np.ndarray
194
+ ): ... # np.ndarray[subclass-specific]
195
+ def factorize(
196
+ self,
197
+ values: np.ndarray, # np.ndarray[subclass-specific]
198
+ na_sentinel: int = ...,
199
+ na_value: object = ...,
200
+ mask=...,
201
+ ignore_na: bool = True,
202
+ ) -> tuple[np.ndarray, npt.NDArray[np.intp]]: ... # np.ndarray[subclass-specific]
203
+
204
+ class Complex128HashTable(HashTable): ...
205
+ class Complex64HashTable(HashTable): ...
206
+ class Float64HashTable(HashTable): ...
207
+ class Float32HashTable(HashTable): ...
208
+
209
+ class Int64HashTable(HashTable):
210
+ # Only Int64HashTable has get_labels_groupby, map_keys_to_values
211
+ def get_labels_groupby(
212
+ self,
213
+ values: npt.NDArray[np.int64], # const int64_t[:]
214
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.int64]]: ...
215
+ def map_keys_to_values(
216
+ self,
217
+ keys: npt.NDArray[np.int64],
218
+ values: npt.NDArray[np.int64], # const int64_t[:]
219
+ ) -> None: ...
220
+
221
+ class Int32HashTable(HashTable): ...
222
+ class Int16HashTable(HashTable): ...
223
+ class Int8HashTable(HashTable): ...
224
+ class UInt64HashTable(HashTable): ...
225
+ class UInt32HashTable(HashTable): ...
226
+ class UInt16HashTable(HashTable): ...
227
+ class UInt8HashTable(HashTable): ...
228
+ class StringHashTable(HashTable): ...
229
+ class PyObjectHashTable(HashTable): ...
230
+ class IntpHashTable(HashTable): ...
231
+
232
+ def duplicated(
233
+ values: np.ndarray,
234
+ keep: Literal["last", "first", False] = ...,
235
+ mask: npt.NDArray[np.bool_] | None = ...,
236
+ ) -> npt.NDArray[np.bool_]: ...
237
+ def mode(
238
+ values: np.ndarray, dropna: bool, mask: npt.NDArray[np.bool_] | None = ...
239
+ ) -> np.ndarray: ...
240
+ def value_count(
241
+ values: np.ndarray,
242
+ dropna: bool,
243
+ mask: npt.NDArray[np.bool_] | None = ...,
244
+ ) -> tuple[np.ndarray, npt.NDArray[np.int64], int]: ... # np.ndarray[same-as-values]
245
+
246
+ # arr and values should have same dtype
247
+ def ismember(
248
+ arr: np.ndarray,
249
+ values: np.ndarray,
250
+ ) -> npt.NDArray[np.bool_]: ...
251
+ def object_hash(obj) -> int: ...
252
+ def objects_are_equal(a, b) -> bool: ...
lib/python3.12/site-packages/pandas/_libs/index.pyi ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ from pandas._typing import npt
4
+
5
+ from pandas import MultiIndex
6
+ from pandas.core.arrays import ExtensionArray
7
+
8
+ multiindex_nulls_shift: int
9
+
10
+ class IndexEngine:
11
+ over_size_threshold: bool
12
+ def __init__(self, values: np.ndarray) -> None: ...
13
+ def __contains__(self, val: object) -> bool: ...
14
+
15
+ # -> int | slice | np.ndarray[bool]
16
+ def get_loc(self, val: object) -> int | slice | np.ndarray: ...
17
+ def sizeof(self, deep: bool = ...) -> int: ...
18
+ def __sizeof__(self) -> int: ...
19
+ @property
20
+ def is_unique(self) -> bool: ...
21
+ @property
22
+ def is_monotonic_increasing(self) -> bool: ...
23
+ @property
24
+ def is_monotonic_decreasing(self) -> bool: ...
25
+ @property
26
+ def is_mapping_populated(self) -> bool: ...
27
+ def clear_mapping(self): ...
28
+ def get_indexer(self, values: np.ndarray) -> npt.NDArray[np.intp]: ...
29
+ def get_indexer_non_unique(
30
+ self,
31
+ targets: np.ndarray,
32
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
33
+
34
+ class MaskedIndexEngine(IndexEngine):
35
+ def __init__(self, values: object) -> None: ...
36
+ def get_indexer_non_unique(
37
+ self, targets: object
38
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
39
+
40
+ class Float64Engine(IndexEngine): ...
41
+ class Float32Engine(IndexEngine): ...
42
+ class Complex128Engine(IndexEngine): ...
43
+ class Complex64Engine(IndexEngine): ...
44
+ class Int64Engine(IndexEngine): ...
45
+ class Int32Engine(IndexEngine): ...
46
+ class Int16Engine(IndexEngine): ...
47
+ class Int8Engine(IndexEngine): ...
48
+ class UInt64Engine(IndexEngine): ...
49
+ class UInt32Engine(IndexEngine): ...
50
+ class UInt16Engine(IndexEngine): ...
51
+ class UInt8Engine(IndexEngine): ...
52
+ class ObjectEngine(IndexEngine): ...
53
+ class DatetimeEngine(Int64Engine): ...
54
+ class TimedeltaEngine(DatetimeEngine): ...
55
+ class PeriodEngine(Int64Engine): ...
56
+ class BoolEngine(UInt8Engine): ...
57
+ class MaskedFloat64Engine(MaskedIndexEngine): ...
58
+ class MaskedFloat32Engine(MaskedIndexEngine): ...
59
+ class MaskedComplex128Engine(MaskedIndexEngine): ...
60
+ class MaskedComplex64Engine(MaskedIndexEngine): ...
61
+ class MaskedInt64Engine(MaskedIndexEngine): ...
62
+ class MaskedInt32Engine(MaskedIndexEngine): ...
63
+ class MaskedInt16Engine(MaskedIndexEngine): ...
64
+ class MaskedInt8Engine(MaskedIndexEngine): ...
65
+ class MaskedUInt64Engine(MaskedIndexEngine): ...
66
+ class MaskedUInt32Engine(MaskedIndexEngine): ...
67
+ class MaskedUInt16Engine(MaskedIndexEngine): ...
68
+ class MaskedUInt8Engine(MaskedIndexEngine): ...
69
+ class MaskedBoolEngine(MaskedUInt8Engine): ...
70
+
71
+ class BaseMultiIndexCodesEngine:
72
+ levels: list[np.ndarray]
73
+ offsets: np.ndarray # ndarray[uint64_t, ndim=1]
74
+
75
+ def __init__(
76
+ self,
77
+ levels: list[np.ndarray], # all entries hashable
78
+ labels: list[np.ndarray], # all entries integer-dtyped
79
+ offsets: np.ndarray, # np.ndarray[np.uint64, ndim=1]
80
+ ) -> None: ...
81
+ def get_indexer(self, target: npt.NDArray[np.object_]) -> npt.NDArray[np.intp]: ...
82
+ def _extract_level_codes(self, target: MultiIndex) -> np.ndarray: ...
83
+
84
+ class ExtensionEngine:
85
+ def __init__(self, values: ExtensionArray) -> None: ...
86
+ def __contains__(self, val: object) -> bool: ...
87
+ def get_loc(self, val: object) -> int | slice | np.ndarray: ...
88
+ def get_indexer(self, values: np.ndarray) -> npt.NDArray[np.intp]: ...
89
+ def get_indexer_non_unique(
90
+ self,
91
+ targets: np.ndarray,
92
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
93
+ @property
94
+ def is_unique(self) -> bool: ...
95
+ @property
96
+ def is_monotonic_increasing(self) -> bool: ...
97
+ @property
98
+ def is_monotonic_decreasing(self) -> bool: ...
99
+ def sizeof(self, deep: bool = ...) -> int: ...
100
+ def clear_mapping(self): ...
lib/python3.12/site-packages/pandas/_libs/indexing.cpython-312-x86_64-linux-gnu.so ADDED
Binary file (70.7 kB). View file
 
lib/python3.12/site-packages/pandas/_libs/indexing.pyi ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import (
2
+ Generic,
3
+ TypeVar,
4
+ )
5
+
6
+ from pandas.core.indexing import IndexingMixin
7
+
8
+ _IndexingMixinT = TypeVar("_IndexingMixinT", bound=IndexingMixin)
9
+
10
+ class NDFrameIndexerBase(Generic[_IndexingMixinT]):
11
+ name: str
12
+ # in practice obj is either a DataFrame or a Series
13
+ obj: _IndexingMixinT
14
+
15
+ def __init__(self, name: str, obj: _IndexingMixinT) -> None: ...
16
+ @property
17
+ def ndim(self) -> int: ...
lib/python3.12/site-packages/pandas/_libs/internals.pyi ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import (
2
+ Iterator,
3
+ Sequence,
4
+ final,
5
+ overload,
6
+ )
7
+ import weakref
8
+
9
+ import numpy as np
10
+
11
+ from pandas._typing import (
12
+ ArrayLike,
13
+ Self,
14
+ npt,
15
+ )
16
+
17
+ from pandas import Index
18
+ from pandas.core.internals.blocks import Block as B
19
+
20
+ def slice_len(slc: slice, objlen: int = ...) -> int: ...
21
+ def get_concat_blkno_indexers(
22
+ blknos_list: list[npt.NDArray[np.intp]],
23
+ ) -> list[tuple[npt.NDArray[np.intp], BlockPlacement]]: ...
24
+ def get_blkno_indexers(
25
+ blknos: np.ndarray, # int64_t[:]
26
+ group: bool = ...,
27
+ ) -> list[tuple[int, slice | np.ndarray]]: ...
28
+ def get_blkno_placements(
29
+ blknos: np.ndarray,
30
+ group: bool = ...,
31
+ ) -> Iterator[tuple[int, BlockPlacement]]: ...
32
+ def update_blklocs_and_blknos(
33
+ blklocs: npt.NDArray[np.intp],
34
+ blknos: npt.NDArray[np.intp],
35
+ loc: int,
36
+ nblocks: int,
37
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
38
+ @final
39
+ class BlockPlacement:
40
+ def __init__(self, val: int | slice | np.ndarray) -> None: ...
41
+ @property
42
+ def indexer(self) -> np.ndarray | slice: ...
43
+ @property
44
+ def as_array(self) -> np.ndarray: ...
45
+ @property
46
+ def as_slice(self) -> slice: ...
47
+ @property
48
+ def is_slice_like(self) -> bool: ...
49
+ @overload
50
+ def __getitem__(
51
+ self, loc: slice | Sequence[int] | npt.NDArray[np.intp]
52
+ ) -> BlockPlacement: ...
53
+ @overload
54
+ def __getitem__(self, loc: int) -> int: ...
55
+ def __iter__(self) -> Iterator[int]: ...
56
+ def __len__(self) -> int: ...
57
+ def delete(self, loc) -> BlockPlacement: ...
58
+ def add(self, other) -> BlockPlacement: ...
59
+ def append(self, others: list[BlockPlacement]) -> BlockPlacement: ...
60
+ def tile_for_unstack(self, factor: int) -> npt.NDArray[np.intp]: ...
61
+
62
+ class Block:
63
+ _mgr_locs: BlockPlacement
64
+ ndim: int
65
+ values: ArrayLike
66
+ refs: BlockValuesRefs
67
+ def __init__(
68
+ self,
69
+ values: ArrayLike,
70
+ placement: BlockPlacement,
71
+ ndim: int,
72
+ refs: BlockValuesRefs | None = ...,
73
+ ) -> None: ...
74
+ def slice_block_rows(self, slicer: slice) -> Self: ...
75
+
76
+ class BlockManager:
77
+ blocks: tuple[B, ...]
78
+ axes: list[Index]
79
+ _known_consolidated: bool
80
+ _is_consolidated: bool
81
+ _blknos: np.ndarray
82
+ _blklocs: np.ndarray
83
+ def __init__(
84
+ self, blocks: tuple[B, ...], axes: list[Index], verify_integrity=...
85
+ ) -> None: ...
86
+ def get_slice(self, slobj: slice, axis: int = ...) -> Self: ...
87
+ def _rebuild_blknos_and_blklocs(self) -> None: ...
88
+
89
+ class BlockValuesRefs:
90
+ referenced_blocks: list[weakref.ref]
91
+ def __init__(self, blk: Block | None = ...) -> None: ...
92
+ def add_reference(self, blk: Block) -> None: ...
93
+ def add_index_reference(self, index: Index) -> None: ...
94
+ def has_reference(self) -> bool: ...
lib/python3.12/site-packages/pandas/_libs/interval.pyi ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import (
2
+ Any,
3
+ Generic,
4
+ TypeVar,
5
+ overload,
6
+ )
7
+
8
+ import numpy as np
9
+ import numpy.typing as npt
10
+
11
+ from pandas._typing import (
12
+ IntervalClosedType,
13
+ Timedelta,
14
+ Timestamp,
15
+ )
16
+
17
+ VALID_CLOSED: frozenset[str]
18
+
19
+ _OrderableScalarT = TypeVar("_OrderableScalarT", int, float)
20
+ _OrderableTimesT = TypeVar("_OrderableTimesT", Timestamp, Timedelta)
21
+ _OrderableT = TypeVar("_OrderableT", int, float, Timestamp, Timedelta)
22
+
23
+ class _LengthDescriptor:
24
+ @overload
25
+ def __get__(
26
+ self, instance: Interval[_OrderableScalarT], owner: Any
27
+ ) -> _OrderableScalarT: ...
28
+ @overload
29
+ def __get__(
30
+ self, instance: Interval[_OrderableTimesT], owner: Any
31
+ ) -> Timedelta: ...
32
+
33
+ class _MidDescriptor:
34
+ @overload
35
+ def __get__(self, instance: Interval[_OrderableScalarT], owner: Any) -> float: ...
36
+ @overload
37
+ def __get__(
38
+ self, instance: Interval[_OrderableTimesT], owner: Any
39
+ ) -> _OrderableTimesT: ...
40
+
41
+ class IntervalMixin:
42
+ @property
43
+ def closed_left(self) -> bool: ...
44
+ @property
45
+ def closed_right(self) -> bool: ...
46
+ @property
47
+ def open_left(self) -> bool: ...
48
+ @property
49
+ def open_right(self) -> bool: ...
50
+ @property
51
+ def is_empty(self) -> bool: ...
52
+ def _check_closed_matches(self, other: IntervalMixin, name: str = ...) -> None: ...
53
+
54
+ class Interval(IntervalMixin, Generic[_OrderableT]):
55
+ @property
56
+ def left(self: Interval[_OrderableT]) -> _OrderableT: ...
57
+ @property
58
+ def right(self: Interval[_OrderableT]) -> _OrderableT: ...
59
+ @property
60
+ def closed(self) -> IntervalClosedType: ...
61
+ mid: _MidDescriptor
62
+ length: _LengthDescriptor
63
+ def __init__(
64
+ self,
65
+ left: _OrderableT,
66
+ right: _OrderableT,
67
+ closed: IntervalClosedType = ...,
68
+ ) -> None: ...
69
+ def __hash__(self) -> int: ...
70
+ @overload
71
+ def __contains__(
72
+ self: Interval[Timedelta], key: Timedelta | Interval[Timedelta]
73
+ ) -> bool: ...
74
+ @overload
75
+ def __contains__(
76
+ self: Interval[Timestamp], key: Timestamp | Interval[Timestamp]
77
+ ) -> bool: ...
78
+ @overload
79
+ def __contains__(
80
+ self: Interval[_OrderableScalarT],
81
+ key: _OrderableScalarT | Interval[_OrderableScalarT],
82
+ ) -> bool: ...
83
+ @overload
84
+ def __add__(
85
+ self: Interval[_OrderableTimesT], y: Timedelta
86
+ ) -> Interval[_OrderableTimesT]: ...
87
+ @overload
88
+ def __add__(
89
+ self: Interval[int], y: _OrderableScalarT
90
+ ) -> Interval[_OrderableScalarT]: ...
91
+ @overload
92
+ def __add__(self: Interval[float], y: float) -> Interval[float]: ...
93
+ @overload
94
+ def __radd__(
95
+ self: Interval[_OrderableTimesT], y: Timedelta
96
+ ) -> Interval[_OrderableTimesT]: ...
97
+ @overload
98
+ def __radd__(
99
+ self: Interval[int], y: _OrderableScalarT
100
+ ) -> Interval[_OrderableScalarT]: ...
101
+ @overload
102
+ def __radd__(self: Interval[float], y: float) -> Interval[float]: ...
103
+ @overload
104
+ def __sub__(
105
+ self: Interval[_OrderableTimesT], y: Timedelta
106
+ ) -> Interval[_OrderableTimesT]: ...
107
+ @overload
108
+ def __sub__(
109
+ self: Interval[int], y: _OrderableScalarT
110
+ ) -> Interval[_OrderableScalarT]: ...
111
+ @overload
112
+ def __sub__(self: Interval[float], y: float) -> Interval[float]: ...
113
+ @overload
114
+ def __rsub__(
115
+ self: Interval[_OrderableTimesT], y: Timedelta
116
+ ) -> Interval[_OrderableTimesT]: ...
117
+ @overload
118
+ def __rsub__(
119
+ self: Interval[int], y: _OrderableScalarT
120
+ ) -> Interval[_OrderableScalarT]: ...
121
+ @overload
122
+ def __rsub__(self: Interval[float], y: float) -> Interval[float]: ...
123
+ @overload
124
+ def __mul__(
125
+ self: Interval[int], y: _OrderableScalarT
126
+ ) -> Interval[_OrderableScalarT]: ...
127
+ @overload
128
+ def __mul__(self: Interval[float], y: float) -> Interval[float]: ...
129
+ @overload
130
+ def __rmul__(
131
+ self: Interval[int], y: _OrderableScalarT
132
+ ) -> Interval[_OrderableScalarT]: ...
133
+ @overload
134
+ def __rmul__(self: Interval[float], y: float) -> Interval[float]: ...
135
+ @overload
136
+ def __truediv__(
137
+ self: Interval[int], y: _OrderableScalarT
138
+ ) -> Interval[_OrderableScalarT]: ...
139
+ @overload
140
+ def __truediv__(self: Interval[float], y: float) -> Interval[float]: ...
141
+ @overload
142
+ def __floordiv__(
143
+ self: Interval[int], y: _OrderableScalarT
144
+ ) -> Interval[_OrderableScalarT]: ...
145
+ @overload
146
+ def __floordiv__(self: Interval[float], y: float) -> Interval[float]: ...
147
+ def overlaps(self: Interval[_OrderableT], other: Interval[_OrderableT]) -> bool: ...
148
+
149
+ def intervals_to_interval_bounds(
150
+ intervals: np.ndarray, validate_closed: bool = ...
151
+ ) -> tuple[np.ndarray, np.ndarray, IntervalClosedType]: ...
152
+
153
+ class IntervalTree(IntervalMixin):
154
+ def __init__(
155
+ self,
156
+ left: np.ndarray,
157
+ right: np.ndarray,
158
+ closed: IntervalClosedType = ...,
159
+ leaf_size: int = ...,
160
+ ) -> None: ...
161
+ @property
162
+ def mid(self) -> np.ndarray: ...
163
+ @property
164
+ def length(self) -> np.ndarray: ...
165
+ def get_indexer(self, target) -> npt.NDArray[np.intp]: ...
166
+ def get_indexer_non_unique(
167
+ self, target
168
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
169
+ _na_count: int
170
+ @property
171
+ def is_overlapping(self) -> bool: ...
172
+ @property
173
+ def is_monotonic_increasing(self) -> bool: ...
174
+ def clear_mapping(self) -> None: ...
lib/python3.12/site-packages/pandas/_libs/join.pyi ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ from pandas._typing import npt
4
+
5
+ def inner_join(
6
+ left: np.ndarray, # const intp_t[:]
7
+ right: np.ndarray, # const intp_t[:]
8
+ max_groups: int,
9
+ sort: bool = ...,
10
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
11
+ def left_outer_join(
12
+ left: np.ndarray, # const intp_t[:]
13
+ right: np.ndarray, # const intp_t[:]
14
+ max_groups: int,
15
+ sort: bool = ...,
16
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
17
+ def full_outer_join(
18
+ left: np.ndarray, # const intp_t[:]
19
+ right: np.ndarray, # const intp_t[:]
20
+ max_groups: int,
21
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
22
+ def ffill_indexer(
23
+ indexer: np.ndarray, # const intp_t[:]
24
+ ) -> npt.NDArray[np.intp]: ...
25
+ def left_join_indexer_unique(
26
+ left: np.ndarray, # ndarray[join_t]
27
+ right: np.ndarray, # ndarray[join_t]
28
+ ) -> npt.NDArray[np.intp]: ...
29
+ def left_join_indexer(
30
+ left: np.ndarray, # ndarray[join_t]
31
+ right: np.ndarray, # ndarray[join_t]
32
+ ) -> tuple[
33
+ np.ndarray, # np.ndarray[join_t]
34
+ npt.NDArray[np.intp],
35
+ npt.NDArray[np.intp],
36
+ ]: ...
37
+ def inner_join_indexer(
38
+ left: np.ndarray, # ndarray[join_t]
39
+ right: np.ndarray, # ndarray[join_t]
40
+ ) -> tuple[
41
+ np.ndarray, # np.ndarray[join_t]
42
+ npt.NDArray[np.intp],
43
+ npt.NDArray[np.intp],
44
+ ]: ...
45
+ def outer_join_indexer(
46
+ left: np.ndarray, # ndarray[join_t]
47
+ right: np.ndarray, # ndarray[join_t]
48
+ ) -> tuple[
49
+ np.ndarray, # np.ndarray[join_t]
50
+ npt.NDArray[np.intp],
51
+ npt.NDArray[np.intp],
52
+ ]: ...
53
+ def asof_join_backward_on_X_by_Y(
54
+ left_values: np.ndarray, # ndarray[numeric_t]
55
+ right_values: np.ndarray, # ndarray[numeric_t]
56
+ left_by_values: np.ndarray, # const int64_t[:]
57
+ right_by_values: np.ndarray, # const int64_t[:]
58
+ allow_exact_matches: bool = ...,
59
+ tolerance: np.number | float | None = ...,
60
+ use_hashtable: bool = ...,
61
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
62
+ def asof_join_forward_on_X_by_Y(
63
+ left_values: np.ndarray, # ndarray[numeric_t]
64
+ right_values: np.ndarray, # ndarray[numeric_t]
65
+ left_by_values: np.ndarray, # const int64_t[:]
66
+ right_by_values: np.ndarray, # const int64_t[:]
67
+ allow_exact_matches: bool = ...,
68
+ tolerance: np.number | float | None = ...,
69
+ use_hashtable: bool = ...,
70
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
71
+ def asof_join_nearest_on_X_by_Y(
72
+ left_values: np.ndarray, # ndarray[numeric_t]
73
+ right_values: np.ndarray, # ndarray[numeric_t]
74
+ left_by_values: np.ndarray, # const int64_t[:]
75
+ right_by_values: np.ndarray, # const int64_t[:]
76
+ allow_exact_matches: bool = ...,
77
+ tolerance: np.number | float | None = ...,
78
+ use_hashtable: bool = ...,
79
+ ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ...
lib/python3.12/site-packages/pandas/_libs/json.cpython-312-x86_64-linux-gnu.so ADDED
Binary file (64.3 kB). View file
 
lib/python3.12/site-packages/pandas/_libs/json.pyi ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import (
2
+ Any,
3
+ Callable,
4
+ )
5
+
6
+ def ujson_dumps(
7
+ obj: Any,
8
+ ensure_ascii: bool = ...,
9
+ double_precision: int = ...,
10
+ indent: int = ...,
11
+ orient: str = ...,
12
+ date_unit: str = ...,
13
+ iso_dates: bool = ...,
14
+ default_handler: None
15
+ | Callable[[Any], str | float | bool | list | dict | None] = ...,
16
+ ) -> str: ...
17
+ def ujson_loads(
18
+ s: str,
19
+ precise_float: bool = ...,
20
+ numpy: bool = ...,
21
+ dtype: None = ...,
22
+ labelled: bool = ...,
23
+ ) -> Any: ...
lib/python3.12/site-packages/pandas/_libs/lib.pyi ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # TODO(npdtypes): Many types specified here can be made more specific/accurate;
2
+ # the more specific versions are specified in comments
3
+ from decimal import Decimal
4
+ from typing import (
5
+ Any,
6
+ Callable,
7
+ Final,
8
+ Generator,
9
+ Hashable,
10
+ Literal,
11
+ TypeAlias,
12
+ overload,
13
+ )
14
+
15
+ import numpy as np
16
+
17
+ from pandas._libs.interval import Interval
18
+ from pandas._libs.tslibs import Period
19
+ from pandas._typing import (
20
+ ArrayLike,
21
+ DtypeObj,
22
+ TypeGuard,
23
+ npt,
24
+ )
25
+
26
+ # placeholder until we can specify np.ndarray[object, ndim=2]
27
+ ndarray_obj_2d = np.ndarray
28
+
29
+ from enum import Enum
30
+
31
+ class _NoDefault(Enum):
32
+ no_default = ...
33
+
34
+ no_default: Final = _NoDefault.no_default
35
+ NoDefault: TypeAlias = Literal[_NoDefault.no_default]
36
+
37
+ i8max: int
38
+ u8max: int
39
+
40
+ def is_np_dtype(dtype: object, kinds: str | None = ...) -> TypeGuard[np.dtype]: ...
41
+ def item_from_zerodim(val: object) -> object: ...
42
+ def infer_dtype(value: object, skipna: bool = ...) -> str: ...
43
+ def is_iterator(obj: object) -> bool: ...
44
+ def is_scalar(val: object) -> bool: ...
45
+ def is_list_like(obj: object, allow_sets: bool = ...) -> bool: ...
46
+ def is_pyarrow_array(obj: object) -> bool: ...
47
+ def is_period(val: object) -> TypeGuard[Period]: ...
48
+ def is_interval(obj: object) -> TypeGuard[Interval]: ...
49
+ def is_decimal(obj: object) -> TypeGuard[Decimal]: ...
50
+ def is_complex(obj: object) -> TypeGuard[complex]: ...
51
+ def is_bool(obj: object) -> TypeGuard[bool | np.bool_]: ...
52
+ def is_integer(obj: object) -> TypeGuard[int | np.integer]: ...
53
+ def is_int_or_none(obj) -> bool: ...
54
+ def is_float(obj: object) -> TypeGuard[float]: ...
55
+ def is_interval_array(values: np.ndarray) -> bool: ...
56
+ def is_datetime64_array(values: np.ndarray, skipna: bool = True) -> bool: ...
57
+ def is_timedelta_or_timedelta64_array(
58
+ values: np.ndarray, skipna: bool = True
59
+ ) -> bool: ...
60
+ def is_datetime_with_singletz_array(values: np.ndarray) -> bool: ...
61
+ def is_time_array(values: np.ndarray, skipna: bool = ...): ...
62
+ def is_date_array(values: np.ndarray, skipna: bool = ...): ...
63
+ def is_datetime_array(values: np.ndarray, skipna: bool = ...): ...
64
+ def is_string_array(values: np.ndarray, skipna: bool = ...): ...
65
+ def is_float_array(values: np.ndarray): ...
66
+ def is_integer_array(values: np.ndarray, skipna: bool = ...): ...
67
+ def is_bool_array(values: np.ndarray, skipna: bool = ...): ...
68
+ def fast_multiget(
69
+ mapping: dict,
70
+ keys: np.ndarray, # object[:]
71
+ default=...,
72
+ ) -> np.ndarray: ...
73
+ def fast_unique_multiple_list_gen(gen: Generator, sort: bool = ...) -> list: ...
74
+ def fast_unique_multiple_list(lists: list, sort: bool | None = ...) -> list: ...
75
+ def map_infer(
76
+ arr: np.ndarray,
77
+ f: Callable[[Any], Any],
78
+ convert: bool = ...,
79
+ ignore_na: bool = ...,
80
+ ) -> np.ndarray: ...
81
+ @overload
82
+ def maybe_convert_objects(
83
+ objects: npt.NDArray[np.object_],
84
+ *,
85
+ try_float: bool = ...,
86
+ safe: bool = ...,
87
+ convert_numeric: bool = ...,
88
+ convert_non_numeric: Literal[False] = ...,
89
+ convert_to_nullable_dtype: Literal[False] = ...,
90
+ dtype_if_all_nat: DtypeObj | None = ...,
91
+ ) -> npt.NDArray[np.object_ | np.number]: ...
92
+ @overload
93
+ def maybe_convert_objects(
94
+ objects: npt.NDArray[np.object_],
95
+ *,
96
+ try_float: bool = ...,
97
+ safe: bool = ...,
98
+ convert_numeric: bool = ...,
99
+ convert_non_numeric: bool = ...,
100
+ convert_to_nullable_dtype: Literal[True] = ...,
101
+ dtype_if_all_nat: DtypeObj | None = ...,
102
+ ) -> ArrayLike: ...
103
+ @overload
104
+ def maybe_convert_objects(
105
+ objects: npt.NDArray[np.object_],
106
+ *,
107
+ try_float: bool = ...,
108
+ safe: bool = ...,
109
+ convert_numeric: bool = ...,
110
+ convert_non_numeric: bool = ...,
111
+ convert_to_nullable_dtype: bool = ...,
112
+ dtype_if_all_nat: DtypeObj | None = ...,
113
+ ) -> ArrayLike: ...
114
+ @overload
115
+ def maybe_convert_numeric(
116
+ values: npt.NDArray[np.object_],
117
+ na_values: set,
118
+ convert_empty: bool = ...,
119
+ coerce_numeric: bool = ...,
120
+ convert_to_masked_nullable: Literal[False] = ...,
121
+ ) -> tuple[np.ndarray, None]: ...
122
+ @overload
123
+ def maybe_convert_numeric(
124
+ values: npt.NDArray[np.object_],
125
+ na_values: set,
126
+ convert_empty: bool = ...,
127
+ coerce_numeric: bool = ...,
128
+ *,
129
+ convert_to_masked_nullable: Literal[True],
130
+ ) -> tuple[np.ndarray, np.ndarray]: ...
131
+
132
+ # TODO: restrict `arr`?
133
+ def ensure_string_array(
134
+ arr,
135
+ na_value: object = ...,
136
+ convert_na_value: bool = ...,
137
+ copy: bool = ...,
138
+ skipna: bool = ...,
139
+ ) -> npt.NDArray[np.object_]: ...
140
+ def convert_nans_to_NA(
141
+ arr: npt.NDArray[np.object_],
142
+ ) -> npt.NDArray[np.object_]: ...
143
+ def fast_zip(ndarrays: list) -> npt.NDArray[np.object_]: ...
144
+
145
+ # TODO: can we be more specific about rows?
146
+ def to_object_array_tuples(rows: object) -> ndarray_obj_2d: ...
147
+ def tuples_to_object_array(
148
+ tuples: npt.NDArray[np.object_],
149
+ ) -> ndarray_obj_2d: ...
150
+
151
+ # TODO: can we be more specific about rows?
152
+ def to_object_array(rows: object, min_width: int = ...) -> ndarray_obj_2d: ...
153
+ def dicts_to_array(dicts: list, columns: list) -> ndarray_obj_2d: ...
154
+ def maybe_booleans_to_slice(
155
+ mask: npt.NDArray[np.uint8],
156
+ ) -> slice | npt.NDArray[np.uint8]: ...
157
+ def maybe_indices_to_slice(
158
+ indices: npt.NDArray[np.intp],
159
+ max_len: int,
160
+ ) -> slice | npt.NDArray[np.intp]: ...
161
+ def is_all_arraylike(obj: list) -> bool: ...
162
+
163
+ # -----------------------------------------------------------------
164
+ # Functions which in reality take memoryviews
165
+
166
+ def memory_usage_of_objects(arr: np.ndarray) -> int: ... # object[:] # np.int64
167
+ def map_infer_mask(
168
+ arr: np.ndarray,
169
+ f: Callable[[Any], Any],
170
+ mask: np.ndarray, # const uint8_t[:]
171
+ convert: bool = ...,
172
+ na_value: Any = ...,
173
+ dtype: np.dtype = ...,
174
+ ) -> np.ndarray: ...
175
+ def indices_fast(
176
+ index: npt.NDArray[np.intp],
177
+ labels: np.ndarray, # const int64_t[:]
178
+ keys: list,
179
+ sorted_labels: list[npt.NDArray[np.int64]],
180
+ ) -> dict[Hashable, npt.NDArray[np.intp]]: ...
181
+ def generate_slices(
182
+ labels: np.ndarray, ngroups: int # const intp_t[:]
183
+ ) -> tuple[npt.NDArray[np.int64], npt.NDArray[np.int64]]: ...
184
+ def count_level_2d(
185
+ mask: np.ndarray, # ndarray[uint8_t, ndim=2, cast=True],
186
+ labels: np.ndarray, # const intp_t[:]
187
+ max_bin: int,
188
+ ) -> np.ndarray: ... # np.ndarray[np.int64, ndim=2]
189
+ def get_level_sorter(
190
+ codes: np.ndarray, # const int64_t[:]
191
+ starts: np.ndarray, # const intp_t[:]
192
+ ) -> np.ndarray: ... # np.ndarray[np.intp, ndim=1]
193
+ def generate_bins_dt64(
194
+ values: npt.NDArray[np.int64],
195
+ binner: np.ndarray, # const int64_t[:]
196
+ closed: object = ...,
197
+ hasnans: bool = ...,
198
+ ) -> np.ndarray: ... # np.ndarray[np.int64, ndim=1]
199
+ def array_equivalent_object(
200
+ left: npt.NDArray[np.object_],
201
+ right: npt.NDArray[np.object_],
202
+ ) -> bool: ...
203
+ def has_infs(arr: np.ndarray) -> bool: ... # const floating[:]
204
+ def has_only_ints_or_nan(arr: np.ndarray) -> bool: ... # const floating[:]
205
+ def get_reverse_indexer(
206
+ indexer: np.ndarray, # const intp_t[:]
207
+ length: int,
208
+ ) -> npt.NDArray[np.intp]: ...
209
+ def is_bool_list(obj: list) -> bool: ...
210
+ def dtypes_all_equal(types: list[DtypeObj]) -> bool: ...
211
+ def is_range_indexer(
212
+ left: np.ndarray, n: int # np.ndarray[np.int64, ndim=1]
213
+ ) -> bool: ...
lib/python3.12/site-packages/pandas/_libs/missing.pyi ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from numpy import typing as npt
3
+
4
+ class NAType:
5
+ def __new__(cls, *args, **kwargs): ...
6
+
7
+ NA: NAType
8
+
9
+ def is_matching_na(
10
+ left: object, right: object, nan_matches_none: bool = ...
11
+ ) -> bool: ...
12
+ def isposinf_scalar(val: object) -> bool: ...
13
+ def isneginf_scalar(val: object) -> bool: ...
14
+ def checknull(val: object, inf_as_na: bool = ...) -> bool: ...
15
+ def isnaobj(arr: np.ndarray, inf_as_na: bool = ...) -> npt.NDArray[np.bool_]: ...
16
+ def is_numeric_na(values: np.ndarray) -> npt.NDArray[np.bool_]: ...
lib/python3.12/site-packages/pandas/_libs/ops.pyi ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import (
2
+ Any,
3
+ Callable,
4
+ Iterable,
5
+ Literal,
6
+ TypeAlias,
7
+ overload,
8
+ )
9
+
10
+ import numpy as np
11
+
12
+ from pandas._typing import npt
13
+
14
+ _BinOp: TypeAlias = Callable[[Any, Any], Any]
15
+ _BoolOp: TypeAlias = Callable[[Any, Any], bool]
16
+
17
+ def scalar_compare(
18
+ values: np.ndarray, # object[:]
19
+ val: object,
20
+ op: _BoolOp, # {operator.eq, operator.ne, ...}
21
+ ) -> npt.NDArray[np.bool_]: ...
22
+ def vec_compare(
23
+ left: npt.NDArray[np.object_],
24
+ right: npt.NDArray[np.object_],
25
+ op: _BoolOp, # {operator.eq, operator.ne, ...}
26
+ ) -> npt.NDArray[np.bool_]: ...
27
+ def scalar_binop(
28
+ values: np.ndarray, # object[:]
29
+ val: object,
30
+ op: _BinOp, # binary operator
31
+ ) -> np.ndarray: ...
32
+ def vec_binop(
33
+ left: np.ndarray, # object[:]
34
+ right: np.ndarray, # object[:]
35
+ op: _BinOp, # binary operator
36
+ ) -> np.ndarray: ...
37
+ @overload
38
+ def maybe_convert_bool(
39
+ arr: npt.NDArray[np.object_],
40
+ true_values: Iterable | None = None,
41
+ false_values: Iterable | None = None,
42
+ convert_to_masked_nullable: Literal[False] = ...,
43
+ ) -> tuple[np.ndarray, None]: ...
44
+ @overload
45
+ def maybe_convert_bool(
46
+ arr: npt.NDArray[np.object_],
47
+ true_values: Iterable = ...,
48
+ false_values: Iterable = ...,
49
+ *,
50
+ convert_to_masked_nullable: Literal[True],
51
+ ) -> tuple[np.ndarray, np.ndarray]: ...
lib/python3.12/site-packages/pandas/_libs/ops_dispatch.cpython-312-x86_64-linux-gnu.so ADDED
Binary file (65.8 kB). View file
 
lib/python3.12/site-packages/pandas/_libs/ops_dispatch.pyi ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ def maybe_dispatch_ufunc_to_dunder_op(
4
+ self, ufunc: np.ufunc, method: str, *inputs, **kwargs
5
+ ): ...
lib/python3.12/site-packages/pandas/_libs/pandas_datetime.cpython-312-x86_64-linux-gnu.so ADDED
Binary file (39.3 kB). View file
 
lib/python3.12/site-packages/pandas/_libs/pandas_parser.cpython-312-x86_64-linux-gnu.so ADDED
Binary file (43.4 kB). View file
 
lib/python3.12/site-packages/pandas/_libs/parsers.pyi ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import (
2
+ Hashable,
3
+ Literal,
4
+ )
5
+
6
+ import numpy as np
7
+
8
+ from pandas._typing import (
9
+ ArrayLike,
10
+ Dtype,
11
+ npt,
12
+ )
13
+
14
+ STR_NA_VALUES: set[str]
15
+ DEFAULT_BUFFER_HEURISTIC: int
16
+
17
+ def sanitize_objects(
18
+ values: npt.NDArray[np.object_],
19
+ na_values: set,
20
+ ) -> int: ...
21
+
22
+ class TextReader:
23
+ unnamed_cols: set[str]
24
+ table_width: int # int64_t
25
+ leading_cols: int # int64_t
26
+ header: list[list[int]] # non-negative integers
27
+ def __init__(
28
+ self,
29
+ source,
30
+ delimiter: bytes | str = ..., # single-character only
31
+ header=...,
32
+ header_start: int = ..., # int64_t
33
+ header_end: int = ..., # uint64_t
34
+ index_col=...,
35
+ names=...,
36
+ tokenize_chunksize: int = ..., # int64_t
37
+ delim_whitespace: bool = ...,
38
+ converters=...,
39
+ skipinitialspace: bool = ...,
40
+ escapechar: bytes | str | None = ..., # single-character only
41
+ doublequote: bool = ...,
42
+ quotechar: str | bytes | None = ..., # at most 1 character
43
+ quoting: int = ...,
44
+ lineterminator: bytes | str | None = ..., # at most 1 character
45
+ comment=...,
46
+ decimal: bytes | str = ..., # single-character only
47
+ thousands: bytes | str | None = ..., # single-character only
48
+ dtype: Dtype | dict[Hashable, Dtype] = ...,
49
+ usecols=...,
50
+ error_bad_lines: bool = ...,
51
+ warn_bad_lines: bool = ...,
52
+ na_filter: bool = ...,
53
+ na_values=...,
54
+ na_fvalues=...,
55
+ keep_default_na: bool = ...,
56
+ true_values=...,
57
+ false_values=...,
58
+ allow_leading_cols: bool = ...,
59
+ skiprows=...,
60
+ skipfooter: int = ..., # int64_t
61
+ verbose: bool = ...,
62
+ float_precision: Literal["round_trip", "legacy", "high"] | None = ...,
63
+ skip_blank_lines: bool = ...,
64
+ encoding_errors: bytes | str = ...,
65
+ ) -> None: ...
66
+ def set_noconvert(self, i: int) -> None: ...
67
+ def remove_noconvert(self, i: int) -> None: ...
68
+ def close(self) -> None: ...
69
+ def read(self, rows: int | None = ...) -> dict[int, ArrayLike]: ...
70
+ def read_low_memory(self, rows: int | None) -> list[dict[int, ArrayLike]]: ...
71
+
72
+ # _maybe_upcast, na_values are only exposed for testing
73
+ na_values: dict
74
+
75
+ def _maybe_upcast(
76
+ arr, use_dtype_backend: bool = ..., dtype_backend: str = ...
77
+ ) -> np.ndarray: ...
lib/python3.12/site-packages/pandas/_libs/properties.cpython-312-x86_64-linux-gnu.so ADDED
Binary file (96 kB). View file
 
lib/python3.12/site-packages/pandas/_libs/properties.pyi ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import (
2
+ Sequence,
3
+ overload,
4
+ )
5
+
6
+ from pandas._typing import (
7
+ AnyArrayLike,
8
+ DataFrame,
9
+ Index,
10
+ Series,
11
+ )
12
+
13
+ # note: this is a lie to make type checkers happy (they special
14
+ # case property). cache_readonly uses attribute names similar to
15
+ # property (fget) but it does not provide fset and fdel.
16
+ cache_readonly = property
17
+
18
+ class AxisProperty:
19
+ axis: int
20
+ def __init__(self, axis: int = ..., doc: str = ...) -> None: ...
21
+ @overload
22
+ def __get__(self, obj: DataFrame | Series, type) -> Index: ...
23
+ @overload
24
+ def __get__(self, obj: None, type) -> AxisProperty: ...
25
+ def __set__(
26
+ self, obj: DataFrame | Series, value: AnyArrayLike | Sequence
27
+ ) -> None: ...
lib/python3.12/site-packages/pandas/_libs/reshape.pyi ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ from pandas._typing import npt
4
+
5
+ def unstack(
6
+ values: np.ndarray, # reshape_t[:, :]
7
+ mask: np.ndarray, # const uint8_t[:]
8
+ stride: int,
9
+ length: int,
10
+ width: int,
11
+ new_values: np.ndarray, # reshape_t[:, :]
12
+ new_mask: np.ndarray, # uint8_t[:, :]
13
+ ) -> None: ...
14
+ def explode(
15
+ values: npt.NDArray[np.object_],
16
+ ) -> tuple[npt.NDArray[np.object_], npt.NDArray[np.int64]]: ...
lib/python3.12/site-packages/pandas/_libs/sas.pyi ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from pandas.io.sas.sas7bdat import SAS7BDATReader
2
+
3
+ class Parser:
4
+ def __init__(self, parser: SAS7BDATReader) -> None: ...
5
+ def read(self, nrows: int) -> None: ...
6
+
7
+ def get_subheader_index(signature: bytes) -> int: ...
lib/python3.12/site-packages/pandas/_libs/sparse.pyi ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Sequence
2
+
3
+ import numpy as np
4
+
5
+ from pandas._typing import (
6
+ Self,
7
+ npt,
8
+ )
9
+
10
+ class SparseIndex:
11
+ length: int
12
+ npoints: int
13
+ def __init__(self) -> None: ...
14
+ @property
15
+ def ngaps(self) -> int: ...
16
+ @property
17
+ def nbytes(self) -> int: ...
18
+ @property
19
+ def indices(self) -> npt.NDArray[np.int32]: ...
20
+ def equals(self, other) -> bool: ...
21
+ def lookup(self, index: int) -> np.int32: ...
22
+ def lookup_array(self, indexer: npt.NDArray[np.int32]) -> npt.NDArray[np.int32]: ...
23
+ def to_int_index(self) -> IntIndex: ...
24
+ def to_block_index(self) -> BlockIndex: ...
25
+ def intersect(self, y_: SparseIndex) -> Self: ...
26
+ def make_union(self, y_: SparseIndex) -> Self: ...
27
+
28
+ class IntIndex(SparseIndex):
29
+ indices: npt.NDArray[np.int32]
30
+ def __init__(
31
+ self, length: int, indices: Sequence[int], check_integrity: bool = ...
32
+ ) -> None: ...
33
+
34
+ class BlockIndex(SparseIndex):
35
+ nblocks: int
36
+ blocs: np.ndarray
37
+ blengths: np.ndarray
38
+ def __init__(
39
+ self, length: int, blocs: np.ndarray, blengths: np.ndarray
40
+ ) -> None: ...
41
+
42
+ # Override to have correct parameters
43
+ def intersect(self, other: SparseIndex) -> Self: ...
44
+ def make_union(self, y: SparseIndex) -> Self: ...
45
+
46
+ def make_mask_object_ndarray(
47
+ arr: npt.NDArray[np.object_], fill_value
48
+ ) -> npt.NDArray[np.bool_]: ...
49
+ def get_blocks(
50
+ indices: npt.NDArray[np.int32],
51
+ ) -> tuple[npt.NDArray[np.int32], npt.NDArray[np.int32]]: ...
lib/python3.12/site-packages/pandas/_libs/testing.pyi ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def assert_dict_equal(a, b, compare_keys: bool = ...): ...
2
+ def assert_almost_equal(
3
+ a,
4
+ b,
5
+ rtol: float = ...,
6
+ atol: float = ...,
7
+ check_dtype: bool = ...,
8
+ obj=...,
9
+ lobj=...,
10
+ robj=...,
11
+ index_values=...,
12
+ ): ...
lib/python3.12/site-packages/pandas/_libs/tslib.pyi ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import tzinfo
2
+
3
+ import numpy as np
4
+
5
+ from pandas._typing import npt
6
+
7
+ def format_array_from_datetime(
8
+ values: npt.NDArray[np.int64],
9
+ tz: tzinfo | None = ...,
10
+ format: str | None = ...,
11
+ na_rep: str | float = ...,
12
+ reso: int = ..., # NPY_DATETIMEUNIT
13
+ ) -> npt.NDArray[np.object_]: ...
14
+ def array_with_unit_to_datetime(
15
+ values: npt.NDArray[np.object_],
16
+ unit: str,
17
+ errors: str = ...,
18
+ ) -> tuple[np.ndarray, tzinfo | None]: ...
19
+ def first_non_null(values: np.ndarray) -> int: ...
20
+ def array_to_datetime(
21
+ values: npt.NDArray[np.object_],
22
+ errors: str = ...,
23
+ dayfirst: bool = ...,
24
+ yearfirst: bool = ...,
25
+ utc: bool = ...,
26
+ creso: int = ...,
27
+ ) -> tuple[np.ndarray, tzinfo | None]: ...
28
+
29
+ # returned ndarray may be object dtype or datetime64[ns]
30
+
31
+ def array_to_datetime_with_tz(
32
+ values: npt.NDArray[np.object_],
33
+ tz: tzinfo,
34
+ dayfirst: bool,
35
+ yearfirst: bool,
36
+ creso: int,
37
+ ) -> npt.NDArray[np.int64]: ...
lib/python3.12/site-packages/pandas/_libs/writers.pyi ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ from pandas._typing import ArrayLike
4
+
5
+ def write_csv_rows(
6
+ data: list[ArrayLike],
7
+ data_index: np.ndarray,
8
+ nlevels: int,
9
+ cols: np.ndarray,
10
+ writer: object, # _csv.writer
11
+ ) -> None: ...
12
+ def convert_json_to_lines(arr: str) -> str: ...
13
+ def max_len_string_array(
14
+ arr: np.ndarray, # pandas_string[:]
15
+ ) -> int: ...
16
+ def word_len(val: object) -> int: ...
17
+ def string_array_replace_from_nan_rep(
18
+ arr: np.ndarray, # np.ndarray[object, ndim=1]
19
+ nan_rep: object,
20
+ ) -> None: ...
lib/python3.12/site-packages/pandas/core/__init__.py ADDED
File without changes
lib/python3.12/site-packages/pandas/core/accessor.py ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+
3
+ accessor.py contains base classes for implementing accessor properties
4
+ that can be mixed into or pinned onto other pandas classes.
5
+
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from typing import (
10
+ Callable,
11
+ final,
12
+ )
13
+ import warnings
14
+
15
+ from pandas.util._decorators import doc
16
+ from pandas.util._exceptions import find_stack_level
17
+
18
+
19
+ class DirNamesMixin:
20
+ _accessors: set[str] = set()
21
+ _hidden_attrs: frozenset[str] = frozenset()
22
+
23
+ @final
24
+ def _dir_deletions(self) -> set[str]:
25
+ """
26
+ Delete unwanted __dir__ for this object.
27
+ """
28
+ return self._accessors | self._hidden_attrs
29
+
30
+ def _dir_additions(self) -> set[str]:
31
+ """
32
+ Add additional __dir__ for this object.
33
+ """
34
+ return {accessor for accessor in self._accessors if hasattr(self, accessor)}
35
+
36
+ def __dir__(self) -> list[str]:
37
+ """
38
+ Provide method name lookup and completion.
39
+
40
+ Notes
41
+ -----
42
+ Only provide 'public' methods.
43
+ """
44
+ rv = set(super().__dir__())
45
+ rv = (rv - self._dir_deletions()) | self._dir_additions()
46
+ return sorted(rv)
47
+
48
+
49
+ class PandasDelegate:
50
+ """
51
+ Abstract base class for delegating methods/properties.
52
+ """
53
+
54
+ def _delegate_property_get(self, name: str, *args, **kwargs):
55
+ raise TypeError(f"You cannot access the property {name}")
56
+
57
+ def _delegate_property_set(self, name: str, value, *args, **kwargs):
58
+ raise TypeError(f"The property {name} cannot be set")
59
+
60
+ def _delegate_method(self, name: str, *args, **kwargs):
61
+ raise TypeError(f"You cannot call method {name}")
62
+
63
+ @classmethod
64
+ def _add_delegate_accessors(
65
+ cls,
66
+ delegate,
67
+ accessors: list[str],
68
+ typ: str,
69
+ overwrite: bool = False,
70
+ accessor_mapping: Callable[[str], str] = lambda x: x,
71
+ raise_on_missing: bool = True,
72
+ ) -> None:
73
+ """
74
+ Add accessors to cls from the delegate class.
75
+
76
+ Parameters
77
+ ----------
78
+ cls
79
+ Class to add the methods/properties to.
80
+ delegate
81
+ Class to get methods/properties and doc-strings.
82
+ accessors : list of str
83
+ List of accessors to add.
84
+ typ : {'property', 'method'}
85
+ overwrite : bool, default False
86
+ Overwrite the method/property in the target class if it exists.
87
+ accessor_mapping: Callable, default lambda x: x
88
+ Callable to map the delegate's function to the cls' function.
89
+ raise_on_missing: bool, default True
90
+ Raise if an accessor does not exist on delegate.
91
+ False skips the missing accessor.
92
+ """
93
+
94
+ def _create_delegator_property(name: str):
95
+ def _getter(self):
96
+ return self._delegate_property_get(name)
97
+
98
+ def _setter(self, new_values):
99
+ return self._delegate_property_set(name, new_values)
100
+
101
+ _getter.__name__ = name
102
+ _setter.__name__ = name
103
+
104
+ return property(
105
+ fget=_getter,
106
+ fset=_setter,
107
+ doc=getattr(delegate, accessor_mapping(name)).__doc__,
108
+ )
109
+
110
+ def _create_delegator_method(name: str):
111
+ def f(self, *args, **kwargs):
112
+ return self._delegate_method(name, *args, **kwargs)
113
+
114
+ f.__name__ = name
115
+ f.__doc__ = getattr(delegate, accessor_mapping(name)).__doc__
116
+
117
+ return f
118
+
119
+ for name in accessors:
120
+ if (
121
+ not raise_on_missing
122
+ and getattr(delegate, accessor_mapping(name), None) is None
123
+ ):
124
+ continue
125
+
126
+ if typ == "property":
127
+ f = _create_delegator_property(name)
128
+ else:
129
+ f = _create_delegator_method(name)
130
+
131
+ # don't overwrite existing methods/properties
132
+ if overwrite or not hasattr(cls, name):
133
+ setattr(cls, name, f)
134
+
135
+
136
+ def delegate_names(
137
+ delegate,
138
+ accessors: list[str],
139
+ typ: str,
140
+ overwrite: bool = False,
141
+ accessor_mapping: Callable[[str], str] = lambda x: x,
142
+ raise_on_missing: bool = True,
143
+ ):
144
+ """
145
+ Add delegated names to a class using a class decorator. This provides
146
+ an alternative usage to directly calling `_add_delegate_accessors`
147
+ below a class definition.
148
+
149
+ Parameters
150
+ ----------
151
+ delegate : object
152
+ The class to get methods/properties & doc-strings.
153
+ accessors : Sequence[str]
154
+ List of accessor to add.
155
+ typ : {'property', 'method'}
156
+ overwrite : bool, default False
157
+ Overwrite the method/property in the target class if it exists.
158
+ accessor_mapping: Callable, default lambda x: x
159
+ Callable to map the delegate's function to the cls' function.
160
+ raise_on_missing: bool, default True
161
+ Raise if an accessor does not exist on delegate.
162
+ False skips the missing accessor.
163
+
164
+ Returns
165
+ -------
166
+ callable
167
+ A class decorator.
168
+
169
+ Examples
170
+ --------
171
+ @delegate_names(Categorical, ["categories", "ordered"], "property")
172
+ class CategoricalAccessor(PandasDelegate):
173
+ [...]
174
+ """
175
+
176
+ def add_delegate_accessors(cls):
177
+ cls._add_delegate_accessors(
178
+ delegate,
179
+ accessors,
180
+ typ,
181
+ overwrite=overwrite,
182
+ accessor_mapping=accessor_mapping,
183
+ raise_on_missing=raise_on_missing,
184
+ )
185
+ return cls
186
+
187
+ return add_delegate_accessors
188
+
189
+
190
+ # Ported with modifications from xarray; licence at LICENSES/XARRAY_LICENSE
191
+ # https://github.com/pydata/xarray/blob/master/xarray/core/extensions.py
192
+ # 1. We don't need to catch and re-raise AttributeErrors as RuntimeErrors
193
+ # 2. We use a UserWarning instead of a custom Warning
194
+
195
+
196
+ class CachedAccessor:
197
+ """
198
+ Custom property-like object.
199
+
200
+ A descriptor for caching accessors.
201
+
202
+ Parameters
203
+ ----------
204
+ name : str
205
+ Namespace that will be accessed under, e.g. ``df.foo``.
206
+ accessor : cls
207
+ Class with the extension methods.
208
+
209
+ Notes
210
+ -----
211
+ For accessor, The class's __init__ method assumes that one of
212
+ ``Series``, ``DataFrame`` or ``Index`` as the
213
+ single argument ``data``.
214
+ """
215
+
216
+ def __init__(self, name: str, accessor) -> None:
217
+ self._name = name
218
+ self._accessor = accessor
219
+
220
+ def __get__(self, obj, cls):
221
+ if obj is None:
222
+ # we're accessing the attribute of the class, i.e., Dataset.geo
223
+ return self._accessor
224
+ accessor_obj = self._accessor(obj)
225
+ # Replace the property with the accessor object. Inspired by:
226
+ # https://www.pydanny.com/cached-property.html
227
+ # We need to use object.__setattr__ because we overwrite __setattr__ on
228
+ # NDFrame
229
+ object.__setattr__(obj, self._name, accessor_obj)
230
+ return accessor_obj
231
+
232
+
233
+ @doc(klass="", others="")
234
+ def _register_accessor(name: str, cls):
235
+ """
236
+ Register a custom accessor on {klass} objects.
237
+
238
+ Parameters
239
+ ----------
240
+ name : str
241
+ Name under which the accessor should be registered. A warning is issued
242
+ if this name conflicts with a preexisting attribute.
243
+
244
+ Returns
245
+ -------
246
+ callable
247
+ A class decorator.
248
+
249
+ See Also
250
+ --------
251
+ register_dataframe_accessor : Register a custom accessor on DataFrame objects.
252
+ register_series_accessor : Register a custom accessor on Series objects.
253
+ register_index_accessor : Register a custom accessor on Index objects.
254
+
255
+ Notes
256
+ -----
257
+ When accessed, your accessor will be initialized with the pandas object
258
+ the user is interacting with. So the signature must be
259
+
260
+ .. code-block:: python
261
+
262
+ def __init__(self, pandas_object): # noqa: E999
263
+ ...
264
+
265
+ For consistency with pandas methods, you should raise an ``AttributeError``
266
+ if the data passed to your accessor has an incorrect dtype.
267
+
268
+ >>> pd.Series(['a', 'b']).dt
269
+ Traceback (most recent call last):
270
+ ...
271
+ AttributeError: Can only use .dt accessor with datetimelike values
272
+
273
+ Examples
274
+ --------
275
+ In your library code::
276
+
277
+ import pandas as pd
278
+
279
+ @pd.api.extensions.register_dataframe_accessor("geo")
280
+ class GeoAccessor:
281
+ def __init__(self, pandas_obj):
282
+ self._obj = pandas_obj
283
+
284
+ @property
285
+ def center(self):
286
+ # return the geographic center point of this DataFrame
287
+ lat = self._obj.latitude
288
+ lon = self._obj.longitude
289
+ return (float(lon.mean()), float(lat.mean()))
290
+
291
+ def plot(self):
292
+ # plot this array's data on a map, e.g., using Cartopy
293
+ pass
294
+
295
+ Back in an interactive IPython session:
296
+
297
+ .. code-block:: ipython
298
+
299
+ In [1]: ds = pd.DataFrame({{"longitude": np.linspace(0, 10),
300
+ ...: "latitude": np.linspace(0, 20)}})
301
+ In [2]: ds.geo.center
302
+ Out[2]: (5.0, 10.0)
303
+ In [3]: ds.geo.plot() # plots data on a map
304
+ """
305
+
306
+ def decorator(accessor):
307
+ if hasattr(cls, name):
308
+ warnings.warn(
309
+ f"registration of accessor {repr(accessor)} under name "
310
+ f"{repr(name)} for type {repr(cls)} is overriding a preexisting "
311
+ f"attribute with the same name.",
312
+ UserWarning,
313
+ stacklevel=find_stack_level(),
314
+ )
315
+ setattr(cls, name, CachedAccessor(name, accessor))
316
+ cls._accessors.add(name)
317
+ return accessor
318
+
319
+ return decorator
320
+
321
+
322
+ @doc(_register_accessor, klass="DataFrame")
323
+ def register_dataframe_accessor(name: str):
324
+ from pandas import DataFrame
325
+
326
+ return _register_accessor(name, DataFrame)
327
+
328
+
329
+ @doc(_register_accessor, klass="Series")
330
+ def register_series_accessor(name: str):
331
+ from pandas import Series
332
+
333
+ return _register_accessor(name, Series)
334
+
335
+
336
+ @doc(_register_accessor, klass="Index")
337
+ def register_index_accessor(name: str):
338
+ from pandas import Index
339
+
340
+ return _register_accessor(name, Index)
lib/python3.12/site-packages/pandas/core/algorithms.py ADDED
@@ -0,0 +1,1747 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Generic data algorithms. This module is experimental at the moment and not
3
+ intended for public consumption
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import decimal
8
+ import operator
9
+ from textwrap import dedent
10
+ from typing import (
11
+ TYPE_CHECKING,
12
+ Literal,
13
+ cast,
14
+ )
15
+ import warnings
16
+
17
+ import numpy as np
18
+
19
+ from pandas._libs import (
20
+ algos,
21
+ hashtable as htable,
22
+ iNaT,
23
+ lib,
24
+ )
25
+ from pandas._typing import (
26
+ AnyArrayLike,
27
+ ArrayLike,
28
+ AxisInt,
29
+ DtypeObj,
30
+ TakeIndexer,
31
+ npt,
32
+ )
33
+ from pandas.util._decorators import doc
34
+ from pandas.util._exceptions import find_stack_level
35
+
36
+ from pandas.core.dtypes.cast import (
37
+ construct_1d_object_array_from_listlike,
38
+ np_find_common_type,
39
+ )
40
+ from pandas.core.dtypes.common import (
41
+ ensure_float64,
42
+ ensure_object,
43
+ ensure_platform_int,
44
+ is_array_like,
45
+ is_bool_dtype,
46
+ is_complex_dtype,
47
+ is_dict_like,
48
+ is_extension_array_dtype,
49
+ is_float_dtype,
50
+ is_integer,
51
+ is_integer_dtype,
52
+ is_list_like,
53
+ is_object_dtype,
54
+ is_signed_integer_dtype,
55
+ needs_i8_conversion,
56
+ )
57
+ from pandas.core.dtypes.concat import concat_compat
58
+ from pandas.core.dtypes.dtypes import (
59
+ BaseMaskedDtype,
60
+ CategoricalDtype,
61
+ ExtensionDtype,
62
+ NumpyEADtype,
63
+ )
64
+ from pandas.core.dtypes.generic import (
65
+ ABCDatetimeArray,
66
+ ABCExtensionArray,
67
+ ABCIndex,
68
+ ABCMultiIndex,
69
+ ABCSeries,
70
+ ABCTimedeltaArray,
71
+ )
72
+ from pandas.core.dtypes.missing import (
73
+ isna,
74
+ na_value_for_dtype,
75
+ )
76
+
77
+ from pandas.core.array_algos.take import take_nd
78
+ from pandas.core.construction import (
79
+ array as pd_array,
80
+ ensure_wrapped_if_datetimelike,
81
+ extract_array,
82
+ )
83
+ from pandas.core.indexers import validate_indices
84
+
85
+ if TYPE_CHECKING:
86
+ from pandas._typing import (
87
+ ListLike,
88
+ NumpySorter,
89
+ NumpyValueArrayLike,
90
+ )
91
+
92
+ from pandas import (
93
+ Categorical,
94
+ Index,
95
+ Series,
96
+ )
97
+ from pandas.core.arrays import (
98
+ BaseMaskedArray,
99
+ ExtensionArray,
100
+ )
101
+
102
+
103
+ # --------------- #
104
+ # dtype access #
105
+ # --------------- #
106
+ def _ensure_data(values: ArrayLike) -> np.ndarray:
107
+ """
108
+ routine to ensure that our data is of the correct
109
+ input dtype for lower-level routines
110
+
111
+ This will coerce:
112
+ - ints -> int64
113
+ - uint -> uint64
114
+ - bool -> uint8
115
+ - datetimelike -> i8
116
+ - datetime64tz -> i8 (in local tz)
117
+ - categorical -> codes
118
+
119
+ Parameters
120
+ ----------
121
+ values : np.ndarray or ExtensionArray
122
+
123
+ Returns
124
+ -------
125
+ np.ndarray
126
+ """
127
+
128
+ if not isinstance(values, ABCMultiIndex):
129
+ # extract_array would raise
130
+ values = extract_array(values, extract_numpy=True)
131
+
132
+ if is_object_dtype(values.dtype):
133
+ return ensure_object(np.asarray(values))
134
+
135
+ elif isinstance(values.dtype, BaseMaskedDtype):
136
+ # i.e. BooleanArray, FloatingArray, IntegerArray
137
+ values = cast("BaseMaskedArray", values)
138
+ if not values._hasna:
139
+ # No pd.NAs -> We can avoid an object-dtype cast (and copy) GH#41816
140
+ # recurse to avoid re-implementing logic for eg bool->uint8
141
+ return _ensure_data(values._data)
142
+ return np.asarray(values)
143
+
144
+ elif isinstance(values.dtype, CategoricalDtype):
145
+ # NB: cases that go through here should NOT be using _reconstruct_data
146
+ # on the back-end.
147
+ values = cast("Categorical", values)
148
+ return values.codes
149
+
150
+ elif is_bool_dtype(values.dtype):
151
+ if isinstance(values, np.ndarray):
152
+ # i.e. actually dtype == np.dtype("bool")
153
+ return np.asarray(values).view("uint8")
154
+ else:
155
+ # e.g. Sparse[bool, False] # TODO: no test cases get here
156
+ return np.asarray(values).astype("uint8", copy=False)
157
+
158
+ elif is_integer_dtype(values.dtype):
159
+ return np.asarray(values)
160
+
161
+ elif is_float_dtype(values.dtype):
162
+ # Note: checking `values.dtype == "float128"` raises on Windows and 32bit
163
+ # error: Item "ExtensionDtype" of "Union[Any, ExtensionDtype, dtype[Any]]"
164
+ # has no attribute "itemsize"
165
+ if values.dtype.itemsize in [2, 12, 16]: # type: ignore[union-attr]
166
+ # we dont (yet) have float128 hashtable support
167
+ return ensure_float64(values)
168
+ return np.asarray(values)
169
+
170
+ elif is_complex_dtype(values.dtype):
171
+ return cast(np.ndarray, values)
172
+
173
+ # datetimelike
174
+ elif needs_i8_conversion(values.dtype):
175
+ npvalues = values.view("i8")
176
+ npvalues = cast(np.ndarray, npvalues)
177
+ return npvalues
178
+
179
+ # we have failed, return object
180
+ values = np.asarray(values, dtype=object)
181
+ return ensure_object(values)
182
+
183
+
184
+ def _reconstruct_data(
185
+ values: ArrayLike, dtype: DtypeObj, original: AnyArrayLike
186
+ ) -> ArrayLike:
187
+ """
188
+ reverse of _ensure_data
189
+
190
+ Parameters
191
+ ----------
192
+ values : np.ndarray or ExtensionArray
193
+ dtype : np.dtype or ExtensionDtype
194
+ original : AnyArrayLike
195
+
196
+ Returns
197
+ -------
198
+ ExtensionArray or np.ndarray
199
+ """
200
+ if isinstance(values, ABCExtensionArray) and values.dtype == dtype:
201
+ # Catch DatetimeArray/TimedeltaArray
202
+ return values
203
+
204
+ if not isinstance(dtype, np.dtype):
205
+ # i.e. ExtensionDtype; note we have ruled out above the possibility
206
+ # that values.dtype == dtype
207
+ cls = dtype.construct_array_type()
208
+
209
+ values = cls._from_sequence(values, dtype=dtype)
210
+
211
+ else:
212
+ values = values.astype(dtype, copy=False)
213
+
214
+ return values
215
+
216
+
217
+ def _ensure_arraylike(values, func_name: str) -> ArrayLike:
218
+ """
219
+ ensure that we are arraylike if not already
220
+ """
221
+ if not isinstance(values, (ABCIndex, ABCSeries, ABCExtensionArray, np.ndarray)):
222
+ # GH#52986
223
+ if func_name != "isin-targets":
224
+ # Make an exception for the comps argument in isin.
225
+ warnings.warn(
226
+ f"{func_name} with argument that is not not a Series, Index, "
227
+ "ExtensionArray, or np.ndarray is deprecated and will raise in a "
228
+ "future version.",
229
+ FutureWarning,
230
+ stacklevel=find_stack_level(),
231
+ )
232
+
233
+ inferred = lib.infer_dtype(values, skipna=False)
234
+ if inferred in ["mixed", "string", "mixed-integer"]:
235
+ # "mixed-integer" to ensure we do not cast ["ss", 42] to str GH#22160
236
+ if isinstance(values, tuple):
237
+ values = list(values)
238
+ values = construct_1d_object_array_from_listlike(values)
239
+ else:
240
+ values = np.asarray(values)
241
+ return values
242
+
243
+
244
+ _hashtables = {
245
+ "complex128": htable.Complex128HashTable,
246
+ "complex64": htable.Complex64HashTable,
247
+ "float64": htable.Float64HashTable,
248
+ "float32": htable.Float32HashTable,
249
+ "uint64": htable.UInt64HashTable,
250
+ "uint32": htable.UInt32HashTable,
251
+ "uint16": htable.UInt16HashTable,
252
+ "uint8": htable.UInt8HashTable,
253
+ "int64": htable.Int64HashTable,
254
+ "int32": htable.Int32HashTable,
255
+ "int16": htable.Int16HashTable,
256
+ "int8": htable.Int8HashTable,
257
+ "string": htable.StringHashTable,
258
+ "object": htable.PyObjectHashTable,
259
+ }
260
+
261
+
262
+ def _get_hashtable_algo(values: np.ndarray):
263
+ """
264
+ Parameters
265
+ ----------
266
+ values : np.ndarray
267
+
268
+ Returns
269
+ -------
270
+ htable : HashTable subclass
271
+ values : ndarray
272
+ """
273
+ values = _ensure_data(values)
274
+
275
+ ndtype = _check_object_for_strings(values)
276
+ hashtable = _hashtables[ndtype]
277
+ return hashtable, values
278
+
279
+
280
+ def _check_object_for_strings(values: np.ndarray) -> str:
281
+ """
282
+ Check if we can use string hashtable instead of object hashtable.
283
+
284
+ Parameters
285
+ ----------
286
+ values : ndarray
287
+
288
+ Returns
289
+ -------
290
+ str
291
+ """
292
+ ndtype = values.dtype.name
293
+ if ndtype == "object":
294
+ # it's cheaper to use a String Hash Table than Object; we infer
295
+ # including nulls because that is the only difference between
296
+ # StringHashTable and ObjectHashtable
297
+ if lib.is_string_array(values, skipna=False):
298
+ ndtype = "string"
299
+ return ndtype
300
+
301
+
302
+ # --------------- #
303
+ # top-level algos #
304
+ # --------------- #
305
+
306
+
307
+ def unique(values):
308
+ """
309
+ Return unique values based on a hash table.
310
+
311
+ Uniques are returned in order of appearance. This does NOT sort.
312
+
313
+ Significantly faster than numpy.unique for long enough sequences.
314
+ Includes NA values.
315
+
316
+ Parameters
317
+ ----------
318
+ values : 1d array-like
319
+
320
+ Returns
321
+ -------
322
+ numpy.ndarray or ExtensionArray
323
+
324
+ The return can be:
325
+
326
+ * Index : when the input is an Index
327
+ * Categorical : when the input is a Categorical dtype
328
+ * ndarray : when the input is a Series/ndarray
329
+
330
+ Return numpy.ndarray or ExtensionArray.
331
+
332
+ See Also
333
+ --------
334
+ Index.unique : Return unique values from an Index.
335
+ Series.unique : Return unique values of Series object.
336
+
337
+ Examples
338
+ --------
339
+ >>> pd.unique(pd.Series([2, 1, 3, 3]))
340
+ array([2, 1, 3])
341
+
342
+ >>> pd.unique(pd.Series([2] + [1] * 5))
343
+ array([2, 1])
344
+
345
+ >>> pd.unique(pd.Series([pd.Timestamp("20160101"), pd.Timestamp("20160101")]))
346
+ array(['2016-01-01T00:00:00.000000000'], dtype='datetime64[ns]')
347
+
348
+ >>> pd.unique(
349
+ ... pd.Series(
350
+ ... [
351
+ ... pd.Timestamp("20160101", tz="US/Eastern"),
352
+ ... pd.Timestamp("20160101", tz="US/Eastern"),
353
+ ... ]
354
+ ... )
355
+ ... )
356
+ <DatetimeArray>
357
+ ['2016-01-01 00:00:00-05:00']
358
+ Length: 1, dtype: datetime64[ns, US/Eastern]
359
+
360
+ >>> pd.unique(
361
+ ... pd.Index(
362
+ ... [
363
+ ... pd.Timestamp("20160101", tz="US/Eastern"),
364
+ ... pd.Timestamp("20160101", tz="US/Eastern"),
365
+ ... ]
366
+ ... )
367
+ ... )
368
+ DatetimeIndex(['2016-01-01 00:00:00-05:00'],
369
+ dtype='datetime64[ns, US/Eastern]',
370
+ freq=None)
371
+
372
+ >>> pd.unique(np.array(list("baabc"), dtype="O"))
373
+ array(['b', 'a', 'c'], dtype=object)
374
+
375
+ An unordered Categorical will return categories in the
376
+ order of appearance.
377
+
378
+ >>> pd.unique(pd.Series(pd.Categorical(list("baabc"))))
379
+ ['b', 'a', 'c']
380
+ Categories (3, object): ['a', 'b', 'c']
381
+
382
+ >>> pd.unique(pd.Series(pd.Categorical(list("baabc"), categories=list("abc"))))
383
+ ['b', 'a', 'c']
384
+ Categories (3, object): ['a', 'b', 'c']
385
+
386
+ An ordered Categorical preserves the category ordering.
387
+
388
+ >>> pd.unique(
389
+ ... pd.Series(
390
+ ... pd.Categorical(list("baabc"), categories=list("abc"), ordered=True)
391
+ ... )
392
+ ... )
393
+ ['b', 'a', 'c']
394
+ Categories (3, object): ['a' < 'b' < 'c']
395
+
396
+ An array of tuples
397
+
398
+ >>> pd.unique(pd.Series([("a", "b"), ("b", "a"), ("a", "c"), ("b", "a")]).values)
399
+ array([('a', 'b'), ('b', 'a'), ('a', 'c')], dtype=object)
400
+ """
401
+ return unique_with_mask(values)
402
+
403
+
404
+ def nunique_ints(values: ArrayLike) -> int:
405
+ """
406
+ Return the number of unique values for integer array-likes.
407
+
408
+ Significantly faster than pandas.unique for long enough sequences.
409
+ No checks are done to ensure input is integral.
410
+
411
+ Parameters
412
+ ----------
413
+ values : 1d array-like
414
+
415
+ Returns
416
+ -------
417
+ int : The number of unique values in ``values``
418
+ """
419
+ if len(values) == 0:
420
+ return 0
421
+ values = _ensure_data(values)
422
+ # bincount requires intp
423
+ result = (np.bincount(values.ravel().astype("intp")) != 0).sum()
424
+ return result
425
+
426
+
427
+ def unique_with_mask(values, mask: npt.NDArray[np.bool_] | None = None):
428
+ """See algorithms.unique for docs. Takes a mask for masked arrays."""
429
+ values = _ensure_arraylike(values, func_name="unique")
430
+
431
+ if isinstance(values.dtype, ExtensionDtype):
432
+ # Dispatch to extension dtype's unique.
433
+ return values.unique()
434
+
435
+ original = values
436
+ hashtable, values = _get_hashtable_algo(values)
437
+
438
+ table = hashtable(len(values))
439
+ if mask is None:
440
+ uniques = table.unique(values)
441
+ uniques = _reconstruct_data(uniques, original.dtype, original)
442
+ return uniques
443
+
444
+ else:
445
+ uniques, mask = table.unique(values, mask=mask)
446
+ uniques = _reconstruct_data(uniques, original.dtype, original)
447
+ assert mask is not None # for mypy
448
+ return uniques, mask.astype("bool")
449
+
450
+
451
+ unique1d = unique
452
+
453
+
454
+ _MINIMUM_COMP_ARR_LEN = 1_000_000
455
+
456
+
457
+ def isin(comps: ListLike, values: ListLike) -> npt.NDArray[np.bool_]:
458
+ """
459
+ Compute the isin boolean array.
460
+
461
+ Parameters
462
+ ----------
463
+ comps : list-like
464
+ values : list-like
465
+
466
+ Returns
467
+ -------
468
+ ndarray[bool]
469
+ Same length as `comps`.
470
+ """
471
+ if not is_list_like(comps):
472
+ raise TypeError(
473
+ "only list-like objects are allowed to be passed "
474
+ f"to isin(), you passed a `{type(comps).__name__}`"
475
+ )
476
+ if not is_list_like(values):
477
+ raise TypeError(
478
+ "only list-like objects are allowed to be passed "
479
+ f"to isin(), you passed a `{type(values).__name__}`"
480
+ )
481
+
482
+ if not isinstance(values, (ABCIndex, ABCSeries, ABCExtensionArray, np.ndarray)):
483
+ orig_values = list(values)
484
+ values = _ensure_arraylike(orig_values, func_name="isin-targets")
485
+
486
+ if (
487
+ len(values) > 0
488
+ and values.dtype.kind in "iufcb"
489
+ and not is_signed_integer_dtype(comps)
490
+ ):
491
+ # GH#46485 Use object to avoid upcast to float64 later
492
+ # TODO: Share with _find_common_type_compat
493
+ values = construct_1d_object_array_from_listlike(orig_values)
494
+
495
+ elif isinstance(values, ABCMultiIndex):
496
+ # Avoid raising in extract_array
497
+ values = np.array(values)
498
+ else:
499
+ values = extract_array(values, extract_numpy=True, extract_range=True)
500
+
501
+ comps_array = _ensure_arraylike(comps, func_name="isin")
502
+ comps_array = extract_array(comps_array, extract_numpy=True)
503
+ if not isinstance(comps_array, np.ndarray):
504
+ # i.e. Extension Array
505
+ return comps_array.isin(values)
506
+
507
+ elif needs_i8_conversion(comps_array.dtype):
508
+ # Dispatch to DatetimeLikeArrayMixin.isin
509
+ return pd_array(comps_array).isin(values)
510
+ elif needs_i8_conversion(values.dtype) and not is_object_dtype(comps_array.dtype):
511
+ # e.g. comps_array are integers and values are datetime64s
512
+ return np.zeros(comps_array.shape, dtype=bool)
513
+ # TODO: not quite right ... Sparse/Categorical
514
+ elif needs_i8_conversion(values.dtype):
515
+ return isin(comps_array, values.astype(object))
516
+
517
+ elif isinstance(values.dtype, ExtensionDtype):
518
+ return isin(np.asarray(comps_array), np.asarray(values))
519
+
520
+ # GH16012
521
+ # Ensure np.isin doesn't get object types or it *may* throw an exception
522
+ # Albeit hashmap has O(1) look-up (vs. O(logn) in sorted array),
523
+ # isin is faster for small sizes
524
+ if (
525
+ len(comps_array) > _MINIMUM_COMP_ARR_LEN
526
+ and len(values) <= 26
527
+ and comps_array.dtype != object
528
+ ):
529
+ # If the values include nan we need to check for nan explicitly
530
+ # since np.nan it not equal to np.nan
531
+ if isna(values).any():
532
+
533
+ def f(c, v):
534
+ return np.logical_or(np.isin(c, v).ravel(), np.isnan(c))
535
+
536
+ else:
537
+ f = lambda a, b: np.isin(a, b).ravel()
538
+
539
+ else:
540
+ common = np_find_common_type(values.dtype, comps_array.dtype)
541
+ values = values.astype(common, copy=False)
542
+ comps_array = comps_array.astype(common, copy=False)
543
+ f = htable.ismember
544
+
545
+ return f(comps_array, values)
546
+
547
+
548
+ def factorize_array(
549
+ values: np.ndarray,
550
+ use_na_sentinel: bool = True,
551
+ size_hint: int | None = None,
552
+ na_value: object = None,
553
+ mask: npt.NDArray[np.bool_] | None = None,
554
+ ) -> tuple[npt.NDArray[np.intp], np.ndarray]:
555
+ """
556
+ Factorize a numpy array to codes and uniques.
557
+
558
+ This doesn't do any coercion of types or unboxing before factorization.
559
+
560
+ Parameters
561
+ ----------
562
+ values : ndarray
563
+ use_na_sentinel : bool, default True
564
+ If True, the sentinel -1 will be used for NaN values. If False,
565
+ NaN values will be encoded as non-negative integers and will not drop the
566
+ NaN from the uniques of the values.
567
+ size_hint : int, optional
568
+ Passed through to the hashtable's 'get_labels' method
569
+ na_value : object, optional
570
+ A value in `values` to consider missing. Note: only use this
571
+ parameter when you know that you don't have any values pandas would
572
+ consider missing in the array (NaN for float data, iNaT for
573
+ datetimes, etc.).
574
+ mask : ndarray[bool], optional
575
+ If not None, the mask is used as indicator for missing values
576
+ (True = missing, False = valid) instead of `na_value` or
577
+ condition "val != val".
578
+
579
+ Returns
580
+ -------
581
+ codes : ndarray[np.intp]
582
+ uniques : ndarray
583
+ """
584
+ original = values
585
+ if values.dtype.kind in "mM":
586
+ # _get_hashtable_algo will cast dt64/td64 to i8 via _ensure_data, so we
587
+ # need to do the same to na_value. We are assuming here that the passed
588
+ # na_value is an appropriately-typed NaT.
589
+ # e.g. test_where_datetimelike_categorical
590
+ na_value = iNaT
591
+
592
+ hash_klass, values = _get_hashtable_algo(values)
593
+
594
+ table = hash_klass(size_hint or len(values))
595
+ uniques, codes = table.factorize(
596
+ values,
597
+ na_sentinel=-1,
598
+ na_value=na_value,
599
+ mask=mask,
600
+ ignore_na=use_na_sentinel,
601
+ )
602
+
603
+ # re-cast e.g. i8->dt64/td64, uint8->bool
604
+ uniques = _reconstruct_data(uniques, original.dtype, original)
605
+
606
+ codes = ensure_platform_int(codes)
607
+ return codes, uniques
608
+
609
+
610
+ @doc(
611
+ values=dedent(
612
+ """\
613
+ values : sequence
614
+ A 1-D sequence. Sequences that aren't pandas objects are
615
+ coerced to ndarrays before factorization.
616
+ """
617
+ ),
618
+ sort=dedent(
619
+ """\
620
+ sort : bool, default False
621
+ Sort `uniques` and shuffle `codes` to maintain the
622
+ relationship.
623
+ """
624
+ ),
625
+ size_hint=dedent(
626
+ """\
627
+ size_hint : int, optional
628
+ Hint to the hashtable sizer.
629
+ """
630
+ ),
631
+ )
632
+ def factorize(
633
+ values,
634
+ sort: bool = False,
635
+ use_na_sentinel: bool = True,
636
+ size_hint: int | None = None,
637
+ ) -> tuple[np.ndarray, np.ndarray | Index]:
638
+ """
639
+ Encode the object as an enumerated type or categorical variable.
640
+
641
+ This method is useful for obtaining a numeric representation of an
642
+ array when all that matters is identifying distinct values. `factorize`
643
+ is available as both a top-level function :func:`pandas.factorize`,
644
+ and as a method :meth:`Series.factorize` and :meth:`Index.factorize`.
645
+
646
+ Parameters
647
+ ----------
648
+ {values}{sort}
649
+ use_na_sentinel : bool, default True
650
+ If True, the sentinel -1 will be used for NaN values. If False,
651
+ NaN values will be encoded as non-negative integers and will not drop the
652
+ NaN from the uniques of the values.
653
+
654
+ .. versionadded:: 1.5.0
655
+ {size_hint}\
656
+
657
+ Returns
658
+ -------
659
+ codes : ndarray
660
+ An integer ndarray that's an indexer into `uniques`.
661
+ ``uniques.take(codes)`` will have the same values as `values`.
662
+ uniques : ndarray, Index, or Categorical
663
+ The unique valid values. When `values` is Categorical, `uniques`
664
+ is a Categorical. When `values` is some other pandas object, an
665
+ `Index` is returned. Otherwise, a 1-D ndarray is returned.
666
+
667
+ .. note::
668
+
669
+ Even if there's a missing value in `values`, `uniques` will
670
+ *not* contain an entry for it.
671
+
672
+ See Also
673
+ --------
674
+ cut : Discretize continuous-valued array.
675
+ unique : Find the unique value in an array.
676
+
677
+ Notes
678
+ -----
679
+ Reference :ref:`the user guide <reshaping.factorize>` for more examples.
680
+
681
+ Examples
682
+ --------
683
+ These examples all show factorize as a top-level method like
684
+ ``pd.factorize(values)``. The results are identical for methods like
685
+ :meth:`Series.factorize`.
686
+
687
+ >>> codes, uniques = pd.factorize(np.array(['b', 'b', 'a', 'c', 'b'], dtype="O"))
688
+ >>> codes
689
+ array([0, 0, 1, 2, 0])
690
+ >>> uniques
691
+ array(['b', 'a', 'c'], dtype=object)
692
+
693
+ With ``sort=True``, the `uniques` will be sorted, and `codes` will be
694
+ shuffled so that the relationship is the maintained.
695
+
696
+ >>> codes, uniques = pd.factorize(np.array(['b', 'b', 'a', 'c', 'b'], dtype="O"),
697
+ ... sort=True)
698
+ >>> codes
699
+ array([1, 1, 0, 2, 1])
700
+ >>> uniques
701
+ array(['a', 'b', 'c'], dtype=object)
702
+
703
+ When ``use_na_sentinel=True`` (the default), missing values are indicated in
704
+ the `codes` with the sentinel value ``-1`` and missing values are not
705
+ included in `uniques`.
706
+
707
+ >>> codes, uniques = pd.factorize(np.array(['b', None, 'a', 'c', 'b'], dtype="O"))
708
+ >>> codes
709
+ array([ 0, -1, 1, 2, 0])
710
+ >>> uniques
711
+ array(['b', 'a', 'c'], dtype=object)
712
+
713
+ Thus far, we've only factorized lists (which are internally coerced to
714
+ NumPy arrays). When factorizing pandas objects, the type of `uniques`
715
+ will differ. For Categoricals, a `Categorical` is returned.
716
+
717
+ >>> cat = pd.Categorical(['a', 'a', 'c'], categories=['a', 'b', 'c'])
718
+ >>> codes, uniques = pd.factorize(cat)
719
+ >>> codes
720
+ array([0, 0, 1])
721
+ >>> uniques
722
+ ['a', 'c']
723
+ Categories (3, object): ['a', 'b', 'c']
724
+
725
+ Notice that ``'b'`` is in ``uniques.categories``, despite not being
726
+ present in ``cat.values``.
727
+
728
+ For all other pandas objects, an Index of the appropriate type is
729
+ returned.
730
+
731
+ >>> cat = pd.Series(['a', 'a', 'c'])
732
+ >>> codes, uniques = pd.factorize(cat)
733
+ >>> codes
734
+ array([0, 0, 1])
735
+ >>> uniques
736
+ Index(['a', 'c'], dtype='object')
737
+
738
+ If NaN is in the values, and we want to include NaN in the uniques of the
739
+ values, it can be achieved by setting ``use_na_sentinel=False``.
740
+
741
+ >>> values = np.array([1, 2, 1, np.nan])
742
+ >>> codes, uniques = pd.factorize(values) # default: use_na_sentinel=True
743
+ >>> codes
744
+ array([ 0, 1, 0, -1])
745
+ >>> uniques
746
+ array([1., 2.])
747
+
748
+ >>> codes, uniques = pd.factorize(values, use_na_sentinel=False)
749
+ >>> codes
750
+ array([0, 1, 0, 2])
751
+ >>> uniques
752
+ array([ 1., 2., nan])
753
+ """
754
+ # Implementation notes: This method is responsible for 3 things
755
+ # 1.) coercing data to array-like (ndarray, Index, extension array)
756
+ # 2.) factorizing codes and uniques
757
+ # 3.) Maybe boxing the uniques in an Index
758
+ #
759
+ # Step 2 is dispatched to extension types (like Categorical). They are
760
+ # responsible only for factorization. All data coercion, sorting and boxing
761
+ # should happen here.
762
+ if isinstance(values, (ABCIndex, ABCSeries)):
763
+ return values.factorize(sort=sort, use_na_sentinel=use_na_sentinel)
764
+
765
+ values = _ensure_arraylike(values, func_name="factorize")
766
+ original = values
767
+
768
+ if (
769
+ isinstance(values, (ABCDatetimeArray, ABCTimedeltaArray))
770
+ and values.freq is not None
771
+ ):
772
+ # The presence of 'freq' means we can fast-path sorting and know there
773
+ # aren't NAs
774
+ codes, uniques = values.factorize(sort=sort)
775
+ return codes, uniques
776
+
777
+ elif not isinstance(values, np.ndarray):
778
+ # i.e. ExtensionArray
779
+ codes, uniques = values.factorize(use_na_sentinel=use_na_sentinel)
780
+
781
+ else:
782
+ values = np.asarray(values) # convert DTA/TDA/MultiIndex
783
+
784
+ if not use_na_sentinel and values.dtype == object:
785
+ # factorize can now handle differentiating various types of null values.
786
+ # These can only occur when the array has object dtype.
787
+ # However, for backwards compatibility we only use the null for the
788
+ # provided dtype. This may be revisited in the future, see GH#48476.
789
+ null_mask = isna(values)
790
+ if null_mask.any():
791
+ na_value = na_value_for_dtype(values.dtype, compat=False)
792
+ # Don't modify (potentially user-provided) array
793
+ values = np.where(null_mask, na_value, values)
794
+
795
+ codes, uniques = factorize_array(
796
+ values,
797
+ use_na_sentinel=use_na_sentinel,
798
+ size_hint=size_hint,
799
+ )
800
+
801
+ if sort and len(uniques) > 0:
802
+ uniques, codes = safe_sort(
803
+ uniques,
804
+ codes,
805
+ use_na_sentinel=use_na_sentinel,
806
+ assume_unique=True,
807
+ verify=False,
808
+ )
809
+
810
+ uniques = _reconstruct_data(uniques, original.dtype, original)
811
+
812
+ return codes, uniques
813
+
814
+
815
+ def value_counts(
816
+ values,
817
+ sort: bool = True,
818
+ ascending: bool = False,
819
+ normalize: bool = False,
820
+ bins=None,
821
+ dropna: bool = True,
822
+ ) -> Series:
823
+ """
824
+ Compute a histogram of the counts of non-null values.
825
+
826
+ Parameters
827
+ ----------
828
+ values : ndarray (1-d)
829
+ sort : bool, default True
830
+ Sort by values
831
+ ascending : bool, default False
832
+ Sort in ascending order
833
+ normalize: bool, default False
834
+ If True then compute a relative histogram
835
+ bins : integer, optional
836
+ Rather than count values, group them into half-open bins,
837
+ convenience for pd.cut, only works with numeric data
838
+ dropna : bool, default True
839
+ Don't include counts of NaN
840
+
841
+ Returns
842
+ -------
843
+ Series
844
+ """
845
+ warnings.warn(
846
+ # GH#53493
847
+ "pandas.value_counts is deprecated and will be removed in a "
848
+ "future version. Use pd.Series(obj).value_counts() instead.",
849
+ FutureWarning,
850
+ stacklevel=find_stack_level(),
851
+ )
852
+ return value_counts_internal(
853
+ values,
854
+ sort=sort,
855
+ ascending=ascending,
856
+ normalize=normalize,
857
+ bins=bins,
858
+ dropna=dropna,
859
+ )
860
+
861
+
862
+ def value_counts_internal(
863
+ values,
864
+ sort: bool = True,
865
+ ascending: bool = False,
866
+ normalize: bool = False,
867
+ bins=None,
868
+ dropna: bool = True,
869
+ ) -> Series:
870
+ from pandas import (
871
+ Index,
872
+ Series,
873
+ )
874
+
875
+ index_name = getattr(values, "name", None)
876
+ name = "proportion" if normalize else "count"
877
+
878
+ if bins is not None:
879
+ from pandas.core.reshape.tile import cut
880
+
881
+ if isinstance(values, Series):
882
+ values = values._values
883
+
884
+ try:
885
+ ii = cut(values, bins, include_lowest=True)
886
+ except TypeError as err:
887
+ raise TypeError("bins argument only works with numeric data.") from err
888
+
889
+ # count, remove nulls (from the index), and but the bins
890
+ result = ii.value_counts(dropna=dropna)
891
+ result.name = name
892
+ result = result[result.index.notna()]
893
+ result.index = result.index.astype("interval")
894
+ result = result.sort_index()
895
+
896
+ # if we are dropna and we have NO values
897
+ if dropna and (result._values == 0).all():
898
+ result = result.iloc[0:0]
899
+
900
+ # normalizing is by len of all (regardless of dropna)
901
+ counts = np.array([len(ii)])
902
+
903
+ else:
904
+ if is_extension_array_dtype(values):
905
+ # handle Categorical and sparse,
906
+ result = Series(values, copy=False)._values.value_counts(dropna=dropna)
907
+ result.name = name
908
+ result.index.name = index_name
909
+ counts = result._values
910
+ if not isinstance(counts, np.ndarray):
911
+ # e.g. ArrowExtensionArray
912
+ counts = np.asarray(counts)
913
+
914
+ elif isinstance(values, ABCMultiIndex):
915
+ # GH49558
916
+ levels = list(range(values.nlevels))
917
+ result = (
918
+ Series(index=values, name=name)
919
+ .groupby(level=levels, dropna=dropna)
920
+ .size()
921
+ )
922
+ result.index.names = values.names
923
+ counts = result._values
924
+
925
+ else:
926
+ values = _ensure_arraylike(values, func_name="value_counts")
927
+ keys, counts, _ = value_counts_arraylike(values, dropna)
928
+ if keys.dtype == np.float16:
929
+ keys = keys.astype(np.float32)
930
+
931
+ # For backwards compatibility, we let Index do its normal type
932
+ # inference, _except_ for if if infers from object to bool.
933
+ idx = Index(keys)
934
+ if idx.dtype == bool and keys.dtype == object:
935
+ idx = idx.astype(object)
936
+ elif (
937
+ idx.dtype != keys.dtype # noqa: PLR1714 # # pylint: disable=R1714
938
+ and idx.dtype != "string[pyarrow_numpy]"
939
+ ):
940
+ warnings.warn(
941
+ # GH#56161
942
+ "The behavior of value_counts with object-dtype is deprecated. "
943
+ "In a future version, this will *not* perform dtype inference "
944
+ "on the resulting index. To retain the old behavior, use "
945
+ "`result.index = result.index.infer_objects()`",
946
+ FutureWarning,
947
+ stacklevel=find_stack_level(),
948
+ )
949
+ idx.name = index_name
950
+
951
+ result = Series(counts, index=idx, name=name, copy=False)
952
+
953
+ if sort:
954
+ result = result.sort_values(ascending=ascending)
955
+
956
+ if normalize:
957
+ result = result / counts.sum()
958
+
959
+ return result
960
+
961
+
962
+ # Called once from SparseArray, otherwise could be private
963
+ def value_counts_arraylike(
964
+ values: np.ndarray, dropna: bool, mask: npt.NDArray[np.bool_] | None = None
965
+ ) -> tuple[ArrayLike, npt.NDArray[np.int64], int]:
966
+ """
967
+ Parameters
968
+ ----------
969
+ values : np.ndarray
970
+ dropna : bool
971
+ mask : np.ndarray[bool] or None, default None
972
+
973
+ Returns
974
+ -------
975
+ uniques : np.ndarray
976
+ counts : np.ndarray[np.int64]
977
+ """
978
+ original = values
979
+ values = _ensure_data(values)
980
+
981
+ keys, counts, na_counter = htable.value_count(values, dropna, mask=mask)
982
+
983
+ if needs_i8_conversion(original.dtype):
984
+ # datetime, timedelta, or period
985
+
986
+ if dropna:
987
+ mask = keys != iNaT
988
+ keys, counts = keys[mask], counts[mask]
989
+
990
+ res_keys = _reconstruct_data(keys, original.dtype, original)
991
+ return res_keys, counts, na_counter
992
+
993
+
994
+ def duplicated(
995
+ values: ArrayLike,
996
+ keep: Literal["first", "last", False] = "first",
997
+ mask: npt.NDArray[np.bool_] | None = None,
998
+ ) -> npt.NDArray[np.bool_]:
999
+ """
1000
+ Return boolean ndarray denoting duplicate values.
1001
+
1002
+ Parameters
1003
+ ----------
1004
+ values : np.ndarray or ExtensionArray
1005
+ Array over which to check for duplicate values.
1006
+ keep : {'first', 'last', False}, default 'first'
1007
+ - ``first`` : Mark duplicates as ``True`` except for the first
1008
+ occurrence.
1009
+ - ``last`` : Mark duplicates as ``True`` except for the last
1010
+ occurrence.
1011
+ - False : Mark all duplicates as ``True``.
1012
+ mask : ndarray[bool], optional
1013
+ array indicating which elements to exclude from checking
1014
+
1015
+ Returns
1016
+ -------
1017
+ duplicated : ndarray[bool]
1018
+ """
1019
+ values = _ensure_data(values)
1020
+ return htable.duplicated(values, keep=keep, mask=mask)
1021
+
1022
+
1023
+ def mode(
1024
+ values: ArrayLike, dropna: bool = True, mask: npt.NDArray[np.bool_] | None = None
1025
+ ) -> ArrayLike:
1026
+ """
1027
+ Returns the mode(s) of an array.
1028
+
1029
+ Parameters
1030
+ ----------
1031
+ values : array-like
1032
+ Array over which to check for duplicate values.
1033
+ dropna : bool, default True
1034
+ Don't consider counts of NaN/NaT.
1035
+
1036
+ Returns
1037
+ -------
1038
+ np.ndarray or ExtensionArray
1039
+ """
1040
+ values = _ensure_arraylike(values, func_name="mode")
1041
+ original = values
1042
+
1043
+ if needs_i8_conversion(values.dtype):
1044
+ # Got here with ndarray; dispatch to DatetimeArray/TimedeltaArray.
1045
+ values = ensure_wrapped_if_datetimelike(values)
1046
+ values = cast("ExtensionArray", values)
1047
+ return values._mode(dropna=dropna)
1048
+
1049
+ values = _ensure_data(values)
1050
+
1051
+ npresult, res_mask = htable.mode(values, dropna=dropna, mask=mask)
1052
+ if res_mask is not None:
1053
+ return npresult, res_mask # type: ignore[return-value]
1054
+
1055
+ try:
1056
+ npresult = np.sort(npresult)
1057
+ except TypeError as err:
1058
+ warnings.warn(
1059
+ f"Unable to sort modes: {err}",
1060
+ stacklevel=find_stack_level(),
1061
+ )
1062
+
1063
+ result = _reconstruct_data(npresult, original.dtype, original)
1064
+ return result
1065
+
1066
+
1067
+ def rank(
1068
+ values: ArrayLike,
1069
+ axis: AxisInt = 0,
1070
+ method: str = "average",
1071
+ na_option: str = "keep",
1072
+ ascending: bool = True,
1073
+ pct: bool = False,
1074
+ ) -> npt.NDArray[np.float64]:
1075
+ """
1076
+ Rank the values along a given axis.
1077
+
1078
+ Parameters
1079
+ ----------
1080
+ values : np.ndarray or ExtensionArray
1081
+ Array whose values will be ranked. The number of dimensions in this
1082
+ array must not exceed 2.
1083
+ axis : int, default 0
1084
+ Axis over which to perform rankings.
1085
+ method : {'average', 'min', 'max', 'first', 'dense'}, default 'average'
1086
+ The method by which tiebreaks are broken during the ranking.
1087
+ na_option : {'keep', 'top'}, default 'keep'
1088
+ The method by which NaNs are placed in the ranking.
1089
+ - ``keep``: rank each NaN value with a NaN ranking
1090
+ - ``top``: replace each NaN with either +/- inf so that they
1091
+ there are ranked at the top
1092
+ ascending : bool, default True
1093
+ Whether or not the elements should be ranked in ascending order.
1094
+ pct : bool, default False
1095
+ Whether or not to the display the returned rankings in integer form
1096
+ (e.g. 1, 2, 3) or in percentile form (e.g. 0.333..., 0.666..., 1).
1097
+ """
1098
+ is_datetimelike = needs_i8_conversion(values.dtype)
1099
+ values = _ensure_data(values)
1100
+
1101
+ if values.ndim == 1:
1102
+ ranks = algos.rank_1d(
1103
+ values,
1104
+ is_datetimelike=is_datetimelike,
1105
+ ties_method=method,
1106
+ ascending=ascending,
1107
+ na_option=na_option,
1108
+ pct=pct,
1109
+ )
1110
+ elif values.ndim == 2:
1111
+ ranks = algos.rank_2d(
1112
+ values,
1113
+ axis=axis,
1114
+ is_datetimelike=is_datetimelike,
1115
+ ties_method=method,
1116
+ ascending=ascending,
1117
+ na_option=na_option,
1118
+ pct=pct,
1119
+ )
1120
+ else:
1121
+ raise TypeError("Array with ndim > 2 are not supported.")
1122
+
1123
+ return ranks
1124
+
1125
+
1126
+ # ---- #
1127
+ # take #
1128
+ # ---- #
1129
+
1130
+
1131
+ def take(
1132
+ arr,
1133
+ indices: TakeIndexer,
1134
+ axis: AxisInt = 0,
1135
+ allow_fill: bool = False,
1136
+ fill_value=None,
1137
+ ):
1138
+ """
1139
+ Take elements from an array.
1140
+
1141
+ Parameters
1142
+ ----------
1143
+ arr : array-like or scalar value
1144
+ Non array-likes (sequences/scalars without a dtype) are coerced
1145
+ to an ndarray.
1146
+
1147
+ .. deprecated:: 2.1.0
1148
+ Passing an argument other than a numpy.ndarray, ExtensionArray,
1149
+ Index, or Series is deprecated.
1150
+
1151
+ indices : sequence of int or one-dimensional np.ndarray of int
1152
+ Indices to be taken.
1153
+ axis : int, default 0
1154
+ The axis over which to select values.
1155
+ allow_fill : bool, default False
1156
+ How to handle negative values in `indices`.
1157
+
1158
+ * False: negative values in `indices` indicate positional indices
1159
+ from the right (the default). This is similar to :func:`numpy.take`.
1160
+
1161
+ * True: negative values in `indices` indicate
1162
+ missing values. These values are set to `fill_value`. Any other
1163
+ negative values raise a ``ValueError``.
1164
+
1165
+ fill_value : any, optional
1166
+ Fill value to use for NA-indices when `allow_fill` is True.
1167
+ This may be ``None``, in which case the default NA value for
1168
+ the type (``self.dtype.na_value``) is used.
1169
+
1170
+ For multi-dimensional `arr`, each *element* is filled with
1171
+ `fill_value`.
1172
+
1173
+ Returns
1174
+ -------
1175
+ ndarray or ExtensionArray
1176
+ Same type as the input.
1177
+
1178
+ Raises
1179
+ ------
1180
+ IndexError
1181
+ When `indices` is out of bounds for the array.
1182
+ ValueError
1183
+ When the indexer contains negative values other than ``-1``
1184
+ and `allow_fill` is True.
1185
+
1186
+ Notes
1187
+ -----
1188
+ When `allow_fill` is False, `indices` may be whatever dimensionality
1189
+ is accepted by NumPy for `arr`.
1190
+
1191
+ When `allow_fill` is True, `indices` should be 1-D.
1192
+
1193
+ See Also
1194
+ --------
1195
+ numpy.take : Take elements from an array along an axis.
1196
+
1197
+ Examples
1198
+ --------
1199
+ >>> import pandas as pd
1200
+
1201
+ With the default ``allow_fill=False``, negative numbers indicate
1202
+ positional indices from the right.
1203
+
1204
+ >>> pd.api.extensions.take(np.array([10, 20, 30]), [0, 0, -1])
1205
+ array([10, 10, 30])
1206
+
1207
+ Setting ``allow_fill=True`` will place `fill_value` in those positions.
1208
+
1209
+ >>> pd.api.extensions.take(np.array([10, 20, 30]), [0, 0, -1], allow_fill=True)
1210
+ array([10., 10., nan])
1211
+
1212
+ >>> pd.api.extensions.take(np.array([10, 20, 30]), [0, 0, -1], allow_fill=True,
1213
+ ... fill_value=-10)
1214
+ array([ 10, 10, -10])
1215
+ """
1216
+ if not isinstance(arr, (np.ndarray, ABCExtensionArray, ABCIndex, ABCSeries)):
1217
+ # GH#52981
1218
+ warnings.warn(
1219
+ "pd.api.extensions.take accepting non-standard inputs is deprecated "
1220
+ "and will raise in a future version. Pass either a numpy.ndarray, "
1221
+ "ExtensionArray, Index, or Series instead.",
1222
+ FutureWarning,
1223
+ stacklevel=find_stack_level(),
1224
+ )
1225
+
1226
+ if not is_array_like(arr):
1227
+ arr = np.asarray(arr)
1228
+
1229
+ indices = ensure_platform_int(indices)
1230
+
1231
+ if allow_fill:
1232
+ # Pandas style, -1 means NA
1233
+ validate_indices(indices, arr.shape[axis])
1234
+ result = take_nd(
1235
+ arr, indices, axis=axis, allow_fill=True, fill_value=fill_value
1236
+ )
1237
+ else:
1238
+ # NumPy style
1239
+ result = arr.take(indices, axis=axis)
1240
+ return result
1241
+
1242
+
1243
+ # ------------ #
1244
+ # searchsorted #
1245
+ # ------------ #
1246
+
1247
+
1248
+ def searchsorted(
1249
+ arr: ArrayLike,
1250
+ value: NumpyValueArrayLike | ExtensionArray,
1251
+ side: Literal["left", "right"] = "left",
1252
+ sorter: NumpySorter | None = None,
1253
+ ) -> npt.NDArray[np.intp] | np.intp:
1254
+ """
1255
+ Find indices where elements should be inserted to maintain order.
1256
+
1257
+ Find the indices into a sorted array `arr` (a) such that, if the
1258
+ corresponding elements in `value` were inserted before the indices,
1259
+ the order of `arr` would be preserved.
1260
+
1261
+ Assuming that `arr` is sorted:
1262
+
1263
+ ====== ================================
1264
+ `side` returned index `i` satisfies
1265
+ ====== ================================
1266
+ left ``arr[i-1] < value <= self[i]``
1267
+ right ``arr[i-1] <= value < self[i]``
1268
+ ====== ================================
1269
+
1270
+ Parameters
1271
+ ----------
1272
+ arr: np.ndarray, ExtensionArray, Series
1273
+ Input array. If `sorter` is None, then it must be sorted in
1274
+ ascending order, otherwise `sorter` must be an array of indices
1275
+ that sort it.
1276
+ value : array-like or scalar
1277
+ Values to insert into `arr`.
1278
+ side : {'left', 'right'}, optional
1279
+ If 'left', the index of the first suitable location found is given.
1280
+ If 'right', return the last such index. If there is no suitable
1281
+ index, return either 0 or N (where N is the length of `self`).
1282
+ sorter : 1-D array-like, optional
1283
+ Optional array of integer indices that sort array a into ascending
1284
+ order. They are typically the result of argsort.
1285
+
1286
+ Returns
1287
+ -------
1288
+ array of ints or int
1289
+ If value is array-like, array of insertion points.
1290
+ If value is scalar, a single integer.
1291
+
1292
+ See Also
1293
+ --------
1294
+ numpy.searchsorted : Similar method from NumPy.
1295
+ """
1296
+ if sorter is not None:
1297
+ sorter = ensure_platform_int(sorter)
1298
+
1299
+ if (
1300
+ isinstance(arr, np.ndarray)
1301
+ and arr.dtype.kind in "iu"
1302
+ and (is_integer(value) or is_integer_dtype(value))
1303
+ ):
1304
+ # if `arr` and `value` have different dtypes, `arr` would be
1305
+ # recast by numpy, causing a slow search.
1306
+ # Before searching below, we therefore try to give `value` the
1307
+ # same dtype as `arr`, while guarding against integer overflows.
1308
+ iinfo = np.iinfo(arr.dtype.type)
1309
+ value_arr = np.array([value]) if is_integer(value) else np.array(value)
1310
+ if (value_arr >= iinfo.min).all() and (value_arr <= iinfo.max).all():
1311
+ # value within bounds, so no overflow, so can convert value dtype
1312
+ # to dtype of arr
1313
+ dtype = arr.dtype
1314
+ else:
1315
+ dtype = value_arr.dtype
1316
+
1317
+ if is_integer(value):
1318
+ # We know that value is int
1319
+ value = cast(int, dtype.type(value))
1320
+ else:
1321
+ value = pd_array(cast(ArrayLike, value), dtype=dtype)
1322
+ else:
1323
+ # E.g. if `arr` is an array with dtype='datetime64[ns]'
1324
+ # and `value` is a pd.Timestamp, we may need to convert value
1325
+ arr = ensure_wrapped_if_datetimelike(arr)
1326
+
1327
+ # Argument 1 to "searchsorted" of "ndarray" has incompatible type
1328
+ # "Union[NumpyValueArrayLike, ExtensionArray]"; expected "NumpyValueArrayLike"
1329
+ return arr.searchsorted(value, side=side, sorter=sorter) # type: ignore[arg-type]
1330
+
1331
+
1332
+ # ---- #
1333
+ # diff #
1334
+ # ---- #
1335
+
1336
+ _diff_special = {"float64", "float32", "int64", "int32", "int16", "int8"}
1337
+
1338
+
1339
+ def diff(arr, n: int, axis: AxisInt = 0):
1340
+ """
1341
+ difference of n between self,
1342
+ analogous to s-s.shift(n)
1343
+
1344
+ Parameters
1345
+ ----------
1346
+ arr : ndarray or ExtensionArray
1347
+ n : int
1348
+ number of periods
1349
+ axis : {0, 1}
1350
+ axis to shift on
1351
+ stacklevel : int, default 3
1352
+ The stacklevel for the lost dtype warning.
1353
+
1354
+ Returns
1355
+ -------
1356
+ shifted
1357
+ """
1358
+
1359
+ n = int(n)
1360
+ na = np.nan
1361
+ dtype = arr.dtype
1362
+
1363
+ is_bool = is_bool_dtype(dtype)
1364
+ if is_bool:
1365
+ op = operator.xor
1366
+ else:
1367
+ op = operator.sub
1368
+
1369
+ if isinstance(dtype, NumpyEADtype):
1370
+ # NumpyExtensionArray cannot necessarily hold shifted versions of itself.
1371
+ arr = arr.to_numpy()
1372
+ dtype = arr.dtype
1373
+
1374
+ if not isinstance(arr, np.ndarray):
1375
+ # i.e ExtensionArray
1376
+ if hasattr(arr, f"__{op.__name__}__"):
1377
+ if axis != 0:
1378
+ raise ValueError(f"cannot diff {type(arr).__name__} on axis={axis}")
1379
+ return op(arr, arr.shift(n))
1380
+ else:
1381
+ raise TypeError(
1382
+ f"{type(arr).__name__} has no 'diff' method. "
1383
+ "Convert to a suitable dtype prior to calling 'diff'."
1384
+ )
1385
+
1386
+ is_timedelta = False
1387
+ if arr.dtype.kind in "mM":
1388
+ dtype = np.int64
1389
+ arr = arr.view("i8")
1390
+ na = iNaT
1391
+ is_timedelta = True
1392
+
1393
+ elif is_bool:
1394
+ # We have to cast in order to be able to hold np.nan
1395
+ dtype = np.object_
1396
+
1397
+ elif dtype.kind in "iu":
1398
+ # We have to cast in order to be able to hold np.nan
1399
+
1400
+ # int8, int16 are incompatible with float64,
1401
+ # see https://github.com/cython/cython/issues/2646
1402
+ if arr.dtype.name in ["int8", "int16"]:
1403
+ dtype = np.float32
1404
+ else:
1405
+ dtype = np.float64
1406
+
1407
+ orig_ndim = arr.ndim
1408
+ if orig_ndim == 1:
1409
+ # reshape so we can always use algos.diff_2d
1410
+ arr = arr.reshape(-1, 1)
1411
+ # TODO: require axis == 0
1412
+
1413
+ dtype = np.dtype(dtype)
1414
+ out_arr = np.empty(arr.shape, dtype=dtype)
1415
+
1416
+ na_indexer = [slice(None)] * 2
1417
+ na_indexer[axis] = slice(None, n) if n >= 0 else slice(n, None)
1418
+ out_arr[tuple(na_indexer)] = na
1419
+
1420
+ if arr.dtype.name in _diff_special:
1421
+ # TODO: can diff_2d dtype specialization troubles be fixed by defining
1422
+ # out_arr inside diff_2d?
1423
+ algos.diff_2d(arr, out_arr, n, axis, datetimelike=is_timedelta)
1424
+ else:
1425
+ # To keep mypy happy, _res_indexer is a list while res_indexer is
1426
+ # a tuple, ditto for lag_indexer.
1427
+ _res_indexer = [slice(None)] * 2
1428
+ _res_indexer[axis] = slice(n, None) if n >= 0 else slice(None, n)
1429
+ res_indexer = tuple(_res_indexer)
1430
+
1431
+ _lag_indexer = [slice(None)] * 2
1432
+ _lag_indexer[axis] = slice(None, -n) if n > 0 else slice(-n, None)
1433
+ lag_indexer = tuple(_lag_indexer)
1434
+
1435
+ out_arr[res_indexer] = op(arr[res_indexer], arr[lag_indexer])
1436
+
1437
+ if is_timedelta:
1438
+ out_arr = out_arr.view("timedelta64[ns]")
1439
+
1440
+ if orig_ndim == 1:
1441
+ out_arr = out_arr[:, 0]
1442
+ return out_arr
1443
+
1444
+
1445
+ # --------------------------------------------------------------------
1446
+ # Helper functions
1447
+
1448
+
1449
+ # Note: safe_sort is in algorithms.py instead of sorting.py because it is
1450
+ # low-dependency, is used in this module, and used private methods from
1451
+ # this module.
1452
+ def safe_sort(
1453
+ values: Index | ArrayLike,
1454
+ codes: npt.NDArray[np.intp] | None = None,
1455
+ use_na_sentinel: bool = True,
1456
+ assume_unique: bool = False,
1457
+ verify: bool = True,
1458
+ ) -> AnyArrayLike | tuple[AnyArrayLike, np.ndarray]:
1459
+ """
1460
+ Sort ``values`` and reorder corresponding ``codes``.
1461
+
1462
+ ``values`` should be unique if ``codes`` is not None.
1463
+ Safe for use with mixed types (int, str), orders ints before strs.
1464
+
1465
+ Parameters
1466
+ ----------
1467
+ values : list-like
1468
+ Sequence; must be unique if ``codes`` is not None.
1469
+ codes : np.ndarray[intp] or None, default None
1470
+ Indices to ``values``. All out of bound indices are treated as
1471
+ "not found" and will be masked with ``-1``.
1472
+ use_na_sentinel : bool, default True
1473
+ If True, the sentinel -1 will be used for NaN values. If False,
1474
+ NaN values will be encoded as non-negative integers and will not drop the
1475
+ NaN from the uniques of the values.
1476
+ assume_unique : bool, default False
1477
+ When True, ``values`` are assumed to be unique, which can speed up
1478
+ the calculation. Ignored when ``codes`` is None.
1479
+ verify : bool, default True
1480
+ Check if codes are out of bound for the values and put out of bound
1481
+ codes equal to ``-1``. If ``verify=False``, it is assumed there
1482
+ are no out of bound codes. Ignored when ``codes`` is None.
1483
+
1484
+ Returns
1485
+ -------
1486
+ ordered : AnyArrayLike
1487
+ Sorted ``values``
1488
+ new_codes : ndarray
1489
+ Reordered ``codes``; returned when ``codes`` is not None.
1490
+
1491
+ Raises
1492
+ ------
1493
+ TypeError
1494
+ * If ``values`` is not list-like or if ``codes`` is neither None
1495
+ nor list-like
1496
+ * If ``values`` cannot be sorted
1497
+ ValueError
1498
+ * If ``codes`` is not None and ``values`` contain duplicates.
1499
+ """
1500
+ if not isinstance(values, (np.ndarray, ABCExtensionArray, ABCIndex)):
1501
+ raise TypeError(
1502
+ "Only np.ndarray, ExtensionArray, and Index objects are allowed to "
1503
+ "be passed to safe_sort as values"
1504
+ )
1505
+
1506
+ sorter = None
1507
+ ordered: AnyArrayLike
1508
+
1509
+ if (
1510
+ not isinstance(values.dtype, ExtensionDtype)
1511
+ and lib.infer_dtype(values, skipna=False) == "mixed-integer"
1512
+ ):
1513
+ ordered = _sort_mixed(values)
1514
+ else:
1515
+ try:
1516
+ sorter = values.argsort()
1517
+ ordered = values.take(sorter)
1518
+ except (TypeError, decimal.InvalidOperation):
1519
+ # Previous sorters failed or were not applicable, try `_sort_mixed`
1520
+ # which would work, but which fails for special case of 1d arrays
1521
+ # with tuples.
1522
+ if values.size and isinstance(values[0], tuple):
1523
+ # error: Argument 1 to "_sort_tuples" has incompatible type
1524
+ # "Union[Index, ExtensionArray, ndarray[Any, Any]]"; expected
1525
+ # "ndarray[Any, Any]"
1526
+ ordered = _sort_tuples(values) # type: ignore[arg-type]
1527
+ else:
1528
+ ordered = _sort_mixed(values)
1529
+
1530
+ # codes:
1531
+
1532
+ if codes is None:
1533
+ return ordered
1534
+
1535
+ if not is_list_like(codes):
1536
+ raise TypeError(
1537
+ "Only list-like objects or None are allowed to "
1538
+ "be passed to safe_sort as codes"
1539
+ )
1540
+ codes = ensure_platform_int(np.asarray(codes))
1541
+
1542
+ if not assume_unique and not len(unique(values)) == len(values):
1543
+ raise ValueError("values should be unique if codes is not None")
1544
+
1545
+ if sorter is None:
1546
+ # mixed types
1547
+ # error: Argument 1 to "_get_hashtable_algo" has incompatible type
1548
+ # "Union[Index, ExtensionArray, ndarray[Any, Any]]"; expected
1549
+ # "ndarray[Any, Any]"
1550
+ hash_klass, values = _get_hashtable_algo(values) # type: ignore[arg-type]
1551
+ t = hash_klass(len(values))
1552
+ t.map_locations(values)
1553
+ sorter = ensure_platform_int(t.lookup(ordered))
1554
+
1555
+ if use_na_sentinel:
1556
+ # take_nd is faster, but only works for na_sentinels of -1
1557
+ order2 = sorter.argsort()
1558
+ if verify:
1559
+ mask = (codes < -len(values)) | (codes >= len(values))
1560
+ codes[mask] = 0
1561
+ else:
1562
+ mask = None
1563
+ new_codes = take_nd(order2, codes, fill_value=-1)
1564
+ else:
1565
+ reverse_indexer = np.empty(len(sorter), dtype=int)
1566
+ reverse_indexer.put(sorter, np.arange(len(sorter)))
1567
+ # Out of bound indices will be masked with `-1` next, so we
1568
+ # may deal with them here without performance loss using `mode='wrap'`
1569
+ new_codes = reverse_indexer.take(codes, mode="wrap")
1570
+
1571
+ if use_na_sentinel:
1572
+ mask = codes == -1
1573
+ if verify:
1574
+ mask = mask | (codes < -len(values)) | (codes >= len(values))
1575
+
1576
+ if use_na_sentinel and mask is not None:
1577
+ np.putmask(new_codes, mask, -1)
1578
+
1579
+ return ordered, ensure_platform_int(new_codes)
1580
+
1581
+
1582
+ def _sort_mixed(values) -> AnyArrayLike:
1583
+ """order ints before strings before nulls in 1d arrays"""
1584
+ str_pos = np.array([isinstance(x, str) for x in values], dtype=bool)
1585
+ null_pos = np.array([isna(x) for x in values], dtype=bool)
1586
+ num_pos = ~str_pos & ~null_pos
1587
+ str_argsort = np.argsort(values[str_pos])
1588
+ num_argsort = np.argsort(values[num_pos])
1589
+ # convert boolean arrays to positional indices, then order by underlying values
1590
+ str_locs = str_pos.nonzero()[0].take(str_argsort)
1591
+ num_locs = num_pos.nonzero()[0].take(num_argsort)
1592
+ null_locs = null_pos.nonzero()[0]
1593
+ locs = np.concatenate([num_locs, str_locs, null_locs])
1594
+ return values.take(locs)
1595
+
1596
+
1597
+ def _sort_tuples(values: np.ndarray) -> np.ndarray:
1598
+ """
1599
+ Convert array of tuples (1d) to array of arrays (2d).
1600
+ We need to keep the columns separately as they contain different types and
1601
+ nans (can't use `np.sort` as it may fail when str and nan are mixed in a
1602
+ column as types cannot be compared).
1603
+ """
1604
+ from pandas.core.internals.construction import to_arrays
1605
+ from pandas.core.sorting import lexsort_indexer
1606
+
1607
+ arrays, _ = to_arrays(values, None)
1608
+ indexer = lexsort_indexer(arrays, orders=True)
1609
+ return values[indexer]
1610
+
1611
+
1612
+ def union_with_duplicates(
1613
+ lvals: ArrayLike | Index, rvals: ArrayLike | Index
1614
+ ) -> ArrayLike | Index:
1615
+ """
1616
+ Extracts the union from lvals and rvals with respect to duplicates and nans in
1617
+ both arrays.
1618
+
1619
+ Parameters
1620
+ ----------
1621
+ lvals: np.ndarray or ExtensionArray
1622
+ left values which is ordered in front.
1623
+ rvals: np.ndarray or ExtensionArray
1624
+ right values ordered after lvals.
1625
+
1626
+ Returns
1627
+ -------
1628
+ np.ndarray or ExtensionArray
1629
+ Containing the unsorted union of both arrays.
1630
+
1631
+ Notes
1632
+ -----
1633
+ Caller is responsible for ensuring lvals.dtype == rvals.dtype.
1634
+ """
1635
+ from pandas import Series
1636
+
1637
+ with warnings.catch_warnings():
1638
+ # filter warning from object dtype inference; we will end up discarding
1639
+ # the index here, so the deprecation does not affect the end result here.
1640
+ warnings.filterwarnings(
1641
+ "ignore",
1642
+ "The behavior of value_counts with object-dtype is deprecated",
1643
+ category=FutureWarning,
1644
+ )
1645
+ l_count = value_counts_internal(lvals, dropna=False)
1646
+ r_count = value_counts_internal(rvals, dropna=False)
1647
+ l_count, r_count = l_count.align(r_count, fill_value=0)
1648
+ final_count = np.maximum(l_count.values, r_count.values)
1649
+ final_count = Series(final_count, index=l_count.index, dtype="int", copy=False)
1650
+ if isinstance(lvals, ABCMultiIndex) and isinstance(rvals, ABCMultiIndex):
1651
+ unique_vals = lvals.append(rvals).unique()
1652
+ else:
1653
+ if isinstance(lvals, ABCIndex):
1654
+ lvals = lvals._values
1655
+ if isinstance(rvals, ABCIndex):
1656
+ rvals = rvals._values
1657
+ # error: List item 0 has incompatible type "Union[ExtensionArray,
1658
+ # ndarray[Any, Any], Index]"; expected "Union[ExtensionArray,
1659
+ # ndarray[Any, Any]]"
1660
+ combined = concat_compat([lvals, rvals]) # type: ignore[list-item]
1661
+ unique_vals = unique(combined)
1662
+ unique_vals = ensure_wrapped_if_datetimelike(unique_vals)
1663
+ repeats = final_count.reindex(unique_vals).values
1664
+ return np.repeat(unique_vals, repeats)
1665
+
1666
+
1667
+ def map_array(
1668
+ arr: ArrayLike,
1669
+ mapper,
1670
+ na_action: Literal["ignore"] | None = None,
1671
+ convert: bool = True,
1672
+ ) -> np.ndarray | ExtensionArray | Index:
1673
+ """
1674
+ Map values using an input mapping or function.
1675
+
1676
+ Parameters
1677
+ ----------
1678
+ mapper : function, dict, or Series
1679
+ Mapping correspondence.
1680
+ na_action : {None, 'ignore'}, default None
1681
+ If 'ignore', propagate NA values, without passing them to the
1682
+ mapping correspondence.
1683
+ convert : bool, default True
1684
+ Try to find better dtype for elementwise function results. If
1685
+ False, leave as dtype=object.
1686
+
1687
+ Returns
1688
+ -------
1689
+ Union[ndarray, Index, ExtensionArray]
1690
+ The output of the mapping function applied to the array.
1691
+ If the function returns a tuple with more than one element
1692
+ a MultiIndex will be returned.
1693
+ """
1694
+ if na_action not in (None, "ignore"):
1695
+ msg = f"na_action must either be 'ignore' or None, {na_action} was passed"
1696
+ raise ValueError(msg)
1697
+
1698
+ # we can fastpath dict/Series to an efficient map
1699
+ # as we know that we are not going to have to yield
1700
+ # python types
1701
+ if is_dict_like(mapper):
1702
+ if isinstance(mapper, dict) and hasattr(mapper, "__missing__"):
1703
+ # If a dictionary subclass defines a default value method,
1704
+ # convert mapper to a lookup function (GH #15999).
1705
+ dict_with_default = mapper
1706
+ mapper = lambda x: dict_with_default[
1707
+ np.nan if isinstance(x, float) and np.isnan(x) else x
1708
+ ]
1709
+ else:
1710
+ # Dictionary does not have a default. Thus it's safe to
1711
+ # convert to an Series for efficiency.
1712
+ # we specify the keys here to handle the
1713
+ # possibility that they are tuples
1714
+
1715
+ # The return value of mapping with an empty mapper is
1716
+ # expected to be pd.Series(np.nan, ...). As np.nan is
1717
+ # of dtype float64 the return value of this method should
1718
+ # be float64 as well
1719
+ from pandas import Series
1720
+
1721
+ if len(mapper) == 0:
1722
+ mapper = Series(mapper, dtype=np.float64)
1723
+ else:
1724
+ mapper = Series(mapper)
1725
+
1726
+ if isinstance(mapper, ABCSeries):
1727
+ if na_action == "ignore":
1728
+ mapper = mapper[mapper.index.notna()]
1729
+
1730
+ # Since values were input this means we came from either
1731
+ # a dict or a series and mapper should be an index
1732
+ indexer = mapper.index.get_indexer(arr)
1733
+ new_values = take_nd(mapper._values, indexer)
1734
+
1735
+ return new_values
1736
+
1737
+ if not len(arr):
1738
+ return arr.copy()
1739
+
1740
+ # we must convert to python types
1741
+ values = arr.astype(object, copy=False)
1742
+ if na_action is None:
1743
+ return lib.map_infer(values, mapper, convert=convert)
1744
+ else:
1745
+ return lib.map_infer_mask(
1746
+ values, mapper, mask=isna(values).view(np.uint8), convert=convert
1747
+ )
lib/python3.12/site-packages/pandas/core/api.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pandas._libs import (
2
+ NaT,
3
+ Period,
4
+ Timedelta,
5
+ Timestamp,
6
+ )
7
+ from pandas._libs.missing import NA
8
+
9
+ from pandas.core.dtypes.dtypes import (
10
+ ArrowDtype,
11
+ CategoricalDtype,
12
+ DatetimeTZDtype,
13
+ IntervalDtype,
14
+ PeriodDtype,
15
+ )
16
+ from pandas.core.dtypes.missing import (
17
+ isna,
18
+ isnull,
19
+ notna,
20
+ notnull,
21
+ )
22
+
23
+ from pandas.core.algorithms import (
24
+ factorize,
25
+ unique,
26
+ value_counts,
27
+ )
28
+ from pandas.core.arrays import Categorical
29
+ from pandas.core.arrays.boolean import BooleanDtype
30
+ from pandas.core.arrays.floating import (
31
+ Float32Dtype,
32
+ Float64Dtype,
33
+ )
34
+ from pandas.core.arrays.integer import (
35
+ Int8Dtype,
36
+ Int16Dtype,
37
+ Int32Dtype,
38
+ Int64Dtype,
39
+ UInt8Dtype,
40
+ UInt16Dtype,
41
+ UInt32Dtype,
42
+ UInt64Dtype,
43
+ )
44
+ from pandas.core.arrays.string_ import StringDtype
45
+ from pandas.core.construction import array
46
+ from pandas.core.flags import Flags
47
+ from pandas.core.groupby import (
48
+ Grouper,
49
+ NamedAgg,
50
+ )
51
+ from pandas.core.indexes.api import (
52
+ CategoricalIndex,
53
+ DatetimeIndex,
54
+ Index,
55
+ IntervalIndex,
56
+ MultiIndex,
57
+ PeriodIndex,
58
+ RangeIndex,
59
+ TimedeltaIndex,
60
+ )
61
+ from pandas.core.indexes.datetimes import (
62
+ bdate_range,
63
+ date_range,
64
+ )
65
+ from pandas.core.indexes.interval import (
66
+ Interval,
67
+ interval_range,
68
+ )
69
+ from pandas.core.indexes.period import period_range
70
+ from pandas.core.indexes.timedeltas import timedelta_range
71
+ from pandas.core.indexing import IndexSlice
72
+ from pandas.core.series import Series
73
+ from pandas.core.tools.datetimes import to_datetime
74
+ from pandas.core.tools.numeric import to_numeric
75
+ from pandas.core.tools.timedeltas import to_timedelta
76
+
77
+ from pandas.io.formats.format import set_eng_float_format
78
+ from pandas.tseries.offsets import DateOffset
79
+
80
+ # DataFrame needs to be imported after NamedAgg to avoid a circular import
81
+ from pandas.core.frame import DataFrame # isort:skip
82
+
83
+ __all__ = [
84
+ "array",
85
+ "ArrowDtype",
86
+ "bdate_range",
87
+ "BooleanDtype",
88
+ "Categorical",
89
+ "CategoricalDtype",
90
+ "CategoricalIndex",
91
+ "DataFrame",
92
+ "DateOffset",
93
+ "date_range",
94
+ "DatetimeIndex",
95
+ "DatetimeTZDtype",
96
+ "factorize",
97
+ "Flags",
98
+ "Float32Dtype",
99
+ "Float64Dtype",
100
+ "Grouper",
101
+ "Index",
102
+ "IndexSlice",
103
+ "Int16Dtype",
104
+ "Int32Dtype",
105
+ "Int64Dtype",
106
+ "Int8Dtype",
107
+ "Interval",
108
+ "IntervalDtype",
109
+ "IntervalIndex",
110
+ "interval_range",
111
+ "isna",
112
+ "isnull",
113
+ "MultiIndex",
114
+ "NA",
115
+ "NamedAgg",
116
+ "NaT",
117
+ "notna",
118
+ "notnull",
119
+ "Period",
120
+ "PeriodDtype",
121
+ "PeriodIndex",
122
+ "period_range",
123
+ "RangeIndex",
124
+ "Series",
125
+ "set_eng_float_format",
126
+ "StringDtype",
127
+ "Timedelta",
128
+ "TimedeltaIndex",
129
+ "timedelta_range",
130
+ "Timestamp",
131
+ "to_datetime",
132
+ "to_numeric",
133
+ "to_timedelta",
134
+ "UInt16Dtype",
135
+ "UInt32Dtype",
136
+ "UInt64Dtype",
137
+ "UInt8Dtype",
138
+ "unique",
139
+ "value_counts",
140
+ ]
lib/python3.12/site-packages/pandas/core/apply.py ADDED
@@ -0,0 +1,2062 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import abc
4
+ from collections import defaultdict
5
+ import functools
6
+ from functools import partial
7
+ import inspect
8
+ from typing import (
9
+ TYPE_CHECKING,
10
+ Any,
11
+ Callable,
12
+ Literal,
13
+ cast,
14
+ )
15
+ import warnings
16
+
17
+ import numpy as np
18
+
19
+ from pandas._config import option_context
20
+
21
+ from pandas._libs import lib
22
+ from pandas._libs.internals import BlockValuesRefs
23
+ from pandas._typing import (
24
+ AggFuncType,
25
+ AggFuncTypeBase,
26
+ AggFuncTypeDict,
27
+ AggObjType,
28
+ Axis,
29
+ AxisInt,
30
+ NDFrameT,
31
+ npt,
32
+ )
33
+ from pandas.compat._optional import import_optional_dependency
34
+ from pandas.errors import SpecificationError
35
+ from pandas.util._decorators import cache_readonly
36
+ from pandas.util._exceptions import find_stack_level
37
+
38
+ from pandas.core.dtypes.cast import is_nested_object
39
+ from pandas.core.dtypes.common import (
40
+ is_dict_like,
41
+ is_extension_array_dtype,
42
+ is_list_like,
43
+ is_numeric_dtype,
44
+ is_sequence,
45
+ )
46
+ from pandas.core.dtypes.dtypes import (
47
+ CategoricalDtype,
48
+ ExtensionDtype,
49
+ )
50
+ from pandas.core.dtypes.generic import (
51
+ ABCDataFrame,
52
+ ABCNDFrame,
53
+ ABCSeries,
54
+ )
55
+
56
+ from pandas.core._numba.executor import generate_apply_looper
57
+ import pandas.core.common as com
58
+ from pandas.core.construction import ensure_wrapped_if_datetimelike
59
+
60
+ if TYPE_CHECKING:
61
+ from collections.abc import (
62
+ Generator,
63
+ Hashable,
64
+ Iterable,
65
+ MutableMapping,
66
+ Sequence,
67
+ )
68
+
69
+ from pandas import (
70
+ DataFrame,
71
+ Index,
72
+ Series,
73
+ )
74
+ from pandas.core.groupby import GroupBy
75
+ from pandas.core.resample import Resampler
76
+ from pandas.core.window.rolling import BaseWindow
77
+
78
+
79
+ ResType = dict[int, Any]
80
+
81
+
82
+ def frame_apply(
83
+ obj: DataFrame,
84
+ func: AggFuncType,
85
+ axis: Axis = 0,
86
+ raw: bool = False,
87
+ result_type: str | None = None,
88
+ by_row: Literal[False, "compat"] = "compat",
89
+ engine: str = "python",
90
+ engine_kwargs: dict[str, bool] | None = None,
91
+ args=None,
92
+ kwargs=None,
93
+ ) -> FrameApply:
94
+ """construct and return a row or column based frame apply object"""
95
+ axis = obj._get_axis_number(axis)
96
+ klass: type[FrameApply]
97
+ if axis == 0:
98
+ klass = FrameRowApply
99
+ elif axis == 1:
100
+ klass = FrameColumnApply
101
+
102
+ _, func, _, _ = reconstruct_func(func, **kwargs)
103
+ assert func is not None
104
+
105
+ return klass(
106
+ obj,
107
+ func,
108
+ raw=raw,
109
+ result_type=result_type,
110
+ by_row=by_row,
111
+ engine=engine,
112
+ engine_kwargs=engine_kwargs,
113
+ args=args,
114
+ kwargs=kwargs,
115
+ )
116
+
117
+
118
+ class Apply(metaclass=abc.ABCMeta):
119
+ axis: AxisInt
120
+
121
+ def __init__(
122
+ self,
123
+ obj: AggObjType,
124
+ func: AggFuncType,
125
+ raw: bool,
126
+ result_type: str | None,
127
+ *,
128
+ by_row: Literal[False, "compat", "_compat"] = "compat",
129
+ engine: str = "python",
130
+ engine_kwargs: dict[str, bool] | None = None,
131
+ args,
132
+ kwargs,
133
+ ) -> None:
134
+ self.obj = obj
135
+ self.raw = raw
136
+
137
+ assert by_row is False or by_row in ["compat", "_compat"]
138
+ self.by_row = by_row
139
+
140
+ self.args = args or ()
141
+ self.kwargs = kwargs or {}
142
+
143
+ self.engine = engine
144
+ self.engine_kwargs = {} if engine_kwargs is None else engine_kwargs
145
+
146
+ if result_type not in [None, "reduce", "broadcast", "expand"]:
147
+ raise ValueError(
148
+ "invalid value for result_type, must be one "
149
+ "of {None, 'reduce', 'broadcast', 'expand'}"
150
+ )
151
+
152
+ self.result_type = result_type
153
+
154
+ self.func = func
155
+
156
+ @abc.abstractmethod
157
+ def apply(self) -> DataFrame | Series:
158
+ pass
159
+
160
+ @abc.abstractmethod
161
+ def agg_or_apply_list_like(
162
+ self, op_name: Literal["agg", "apply"]
163
+ ) -> DataFrame | Series:
164
+ pass
165
+
166
+ @abc.abstractmethod
167
+ def agg_or_apply_dict_like(
168
+ self, op_name: Literal["agg", "apply"]
169
+ ) -> DataFrame | Series:
170
+ pass
171
+
172
+ def agg(self) -> DataFrame | Series | None:
173
+ """
174
+ Provide an implementation for the aggregators.
175
+
176
+ Returns
177
+ -------
178
+ Result of aggregation, or None if agg cannot be performed by
179
+ this method.
180
+ """
181
+ obj = self.obj
182
+ func = self.func
183
+ args = self.args
184
+ kwargs = self.kwargs
185
+
186
+ if isinstance(func, str):
187
+ return self.apply_str()
188
+
189
+ if is_dict_like(func):
190
+ return self.agg_dict_like()
191
+ elif is_list_like(func):
192
+ # we require a list, but not a 'str'
193
+ return self.agg_list_like()
194
+
195
+ if callable(func):
196
+ f = com.get_cython_func(func)
197
+ if f and not args and not kwargs:
198
+ warn_alias_replacement(obj, func, f)
199
+ return getattr(obj, f)()
200
+
201
+ # caller can react
202
+ return None
203
+
204
+ def transform(self) -> DataFrame | Series:
205
+ """
206
+ Transform a DataFrame or Series.
207
+
208
+ Returns
209
+ -------
210
+ DataFrame or Series
211
+ Result of applying ``func`` along the given axis of the
212
+ Series or DataFrame.
213
+
214
+ Raises
215
+ ------
216
+ ValueError
217
+ If the transform function fails or does not transform.
218
+ """
219
+ obj = self.obj
220
+ func = self.func
221
+ axis = self.axis
222
+ args = self.args
223
+ kwargs = self.kwargs
224
+
225
+ is_series = obj.ndim == 1
226
+
227
+ if obj._get_axis_number(axis) == 1:
228
+ assert not is_series
229
+ return obj.T.transform(func, 0, *args, **kwargs).T
230
+
231
+ if is_list_like(func) and not is_dict_like(func):
232
+ func = cast(list[AggFuncTypeBase], func)
233
+ # Convert func equivalent dict
234
+ if is_series:
235
+ func = {com.get_callable_name(v) or v: v for v in func}
236
+ else:
237
+ func = {col: func for col in obj}
238
+
239
+ if is_dict_like(func):
240
+ func = cast(AggFuncTypeDict, func)
241
+ return self.transform_dict_like(func)
242
+
243
+ # func is either str or callable
244
+ func = cast(AggFuncTypeBase, func)
245
+ try:
246
+ result = self.transform_str_or_callable(func)
247
+ except TypeError:
248
+ raise
249
+ except Exception as err:
250
+ raise ValueError("Transform function failed") from err
251
+
252
+ # Functions that transform may return empty Series/DataFrame
253
+ # when the dtype is not appropriate
254
+ if (
255
+ isinstance(result, (ABCSeries, ABCDataFrame))
256
+ and result.empty
257
+ and not obj.empty
258
+ ):
259
+ raise ValueError("Transform function failed")
260
+ # error: Argument 1 to "__get__" of "AxisProperty" has incompatible type
261
+ # "Union[Series, DataFrame, GroupBy[Any], SeriesGroupBy,
262
+ # DataFrameGroupBy, BaseWindow, Resampler]"; expected "Union[DataFrame,
263
+ # Series]"
264
+ if not isinstance(result, (ABCSeries, ABCDataFrame)) or not result.index.equals(
265
+ obj.index # type: ignore[arg-type]
266
+ ):
267
+ raise ValueError("Function did not transform")
268
+
269
+ return result
270
+
271
+ def transform_dict_like(self, func) -> DataFrame:
272
+ """
273
+ Compute transform in the case of a dict-like func
274
+ """
275
+ from pandas.core.reshape.concat import concat
276
+
277
+ obj = self.obj
278
+ args = self.args
279
+ kwargs = self.kwargs
280
+
281
+ # transform is currently only for Series/DataFrame
282
+ assert isinstance(obj, ABCNDFrame)
283
+
284
+ if len(func) == 0:
285
+ raise ValueError("No transform functions were provided")
286
+
287
+ func = self.normalize_dictlike_arg("transform", obj, func)
288
+
289
+ results: dict[Hashable, DataFrame | Series] = {}
290
+ for name, how in func.items():
291
+ colg = obj._gotitem(name, ndim=1)
292
+ results[name] = colg.transform(how, 0, *args, **kwargs)
293
+ return concat(results, axis=1)
294
+
295
+ def transform_str_or_callable(self, func) -> DataFrame | Series:
296
+ """
297
+ Compute transform in the case of a string or callable func
298
+ """
299
+ obj = self.obj
300
+ args = self.args
301
+ kwargs = self.kwargs
302
+
303
+ if isinstance(func, str):
304
+ return self._apply_str(obj, func, *args, **kwargs)
305
+
306
+ if not args and not kwargs:
307
+ f = com.get_cython_func(func)
308
+ if f:
309
+ warn_alias_replacement(obj, func, f)
310
+ return getattr(obj, f)()
311
+
312
+ # Two possible ways to use a UDF - apply or call directly
313
+ try:
314
+ return obj.apply(func, args=args, **kwargs)
315
+ except Exception:
316
+ return func(obj, *args, **kwargs)
317
+
318
+ def agg_list_like(self) -> DataFrame | Series:
319
+ """
320
+ Compute aggregation in the case of a list-like argument.
321
+
322
+ Returns
323
+ -------
324
+ Result of aggregation.
325
+ """
326
+ return self.agg_or_apply_list_like(op_name="agg")
327
+
328
+ def compute_list_like(
329
+ self,
330
+ op_name: Literal["agg", "apply"],
331
+ selected_obj: Series | DataFrame,
332
+ kwargs: dict[str, Any],
333
+ ) -> tuple[list[Hashable] | Index, list[Any]]:
334
+ """
335
+ Compute agg/apply results for like-like input.
336
+
337
+ Parameters
338
+ ----------
339
+ op_name : {"agg", "apply"}
340
+ Operation being performed.
341
+ selected_obj : Series or DataFrame
342
+ Data to perform operation on.
343
+ kwargs : dict
344
+ Keyword arguments to pass to the functions.
345
+
346
+ Returns
347
+ -------
348
+ keys : list[Hashable] or Index
349
+ Index labels for result.
350
+ results : list
351
+ Data for result. When aggregating with a Series, this can contain any
352
+ Python objects.
353
+ """
354
+ func = cast(list[AggFuncTypeBase], self.func)
355
+ obj = self.obj
356
+
357
+ results = []
358
+ keys = []
359
+
360
+ # degenerate case
361
+ if selected_obj.ndim == 1:
362
+ for a in func:
363
+ colg = obj._gotitem(selected_obj.name, ndim=1, subset=selected_obj)
364
+ args = (
365
+ [self.axis, *self.args]
366
+ if include_axis(op_name, colg)
367
+ else self.args
368
+ )
369
+ new_res = getattr(colg, op_name)(a, *args, **kwargs)
370
+ results.append(new_res)
371
+
372
+ # make sure we find a good name
373
+ name = com.get_callable_name(a) or a
374
+ keys.append(name)
375
+
376
+ else:
377
+ indices = []
378
+ for index, col in enumerate(selected_obj):
379
+ colg = obj._gotitem(col, ndim=1, subset=selected_obj.iloc[:, index])
380
+ args = (
381
+ [self.axis, *self.args]
382
+ if include_axis(op_name, colg)
383
+ else self.args
384
+ )
385
+ new_res = getattr(colg, op_name)(func, *args, **kwargs)
386
+ results.append(new_res)
387
+ indices.append(index)
388
+ # error: Incompatible types in assignment (expression has type "Any |
389
+ # Index", variable has type "list[Any | Callable[..., Any] | str]")
390
+ keys = selected_obj.columns.take(indices) # type: ignore[assignment]
391
+
392
+ return keys, results
393
+
394
+ def wrap_results_list_like(
395
+ self, keys: Iterable[Hashable], results: list[Series | DataFrame]
396
+ ):
397
+ from pandas.core.reshape.concat import concat
398
+
399
+ obj = self.obj
400
+
401
+ try:
402
+ return concat(results, keys=keys, axis=1, sort=False)
403
+ except TypeError as err:
404
+ # we are concatting non-NDFrame objects,
405
+ # e.g. a list of scalars
406
+ from pandas import Series
407
+
408
+ result = Series(results, index=keys, name=obj.name)
409
+ if is_nested_object(result):
410
+ raise ValueError(
411
+ "cannot combine transform and aggregation operations"
412
+ ) from err
413
+ return result
414
+
415
+ def agg_dict_like(self) -> DataFrame | Series:
416
+ """
417
+ Compute aggregation in the case of a dict-like argument.
418
+
419
+ Returns
420
+ -------
421
+ Result of aggregation.
422
+ """
423
+ return self.agg_or_apply_dict_like(op_name="agg")
424
+
425
+ def compute_dict_like(
426
+ self,
427
+ op_name: Literal["agg", "apply"],
428
+ selected_obj: Series | DataFrame,
429
+ selection: Hashable | Sequence[Hashable],
430
+ kwargs: dict[str, Any],
431
+ ) -> tuple[list[Hashable], list[Any]]:
432
+ """
433
+ Compute agg/apply results for dict-like input.
434
+
435
+ Parameters
436
+ ----------
437
+ op_name : {"agg", "apply"}
438
+ Operation being performed.
439
+ selected_obj : Series or DataFrame
440
+ Data to perform operation on.
441
+ selection : hashable or sequence of hashables
442
+ Used by GroupBy, Window, and Resample if selection is applied to the object.
443
+ kwargs : dict
444
+ Keyword arguments to pass to the functions.
445
+
446
+ Returns
447
+ -------
448
+ keys : list[hashable]
449
+ Index labels for result.
450
+ results : list
451
+ Data for result. When aggregating with a Series, this can contain any
452
+ Python object.
453
+ """
454
+ from pandas.core.groupby.generic import (
455
+ DataFrameGroupBy,
456
+ SeriesGroupBy,
457
+ )
458
+
459
+ obj = self.obj
460
+ is_groupby = isinstance(obj, (DataFrameGroupBy, SeriesGroupBy))
461
+ func = cast(AggFuncTypeDict, self.func)
462
+ func = self.normalize_dictlike_arg(op_name, selected_obj, func)
463
+
464
+ is_non_unique_col = (
465
+ selected_obj.ndim == 2
466
+ and selected_obj.columns.nunique() < len(selected_obj.columns)
467
+ )
468
+
469
+ if selected_obj.ndim == 1:
470
+ # key only used for output
471
+ colg = obj._gotitem(selection, ndim=1)
472
+ results = [getattr(colg, op_name)(how, **kwargs) for _, how in func.items()]
473
+ keys = list(func.keys())
474
+ elif not is_groupby and is_non_unique_col:
475
+ # key used for column selection and output
476
+ # GH#51099
477
+ results = []
478
+ keys = []
479
+ for key, how in func.items():
480
+ indices = selected_obj.columns.get_indexer_for([key])
481
+ labels = selected_obj.columns.take(indices)
482
+ label_to_indices = defaultdict(list)
483
+ for index, label in zip(indices, labels):
484
+ label_to_indices[label].append(index)
485
+
486
+ key_data = [
487
+ getattr(selected_obj._ixs(indice, axis=1), op_name)(how, **kwargs)
488
+ for label, indices in label_to_indices.items()
489
+ for indice in indices
490
+ ]
491
+
492
+ keys += [key] * len(key_data)
493
+ results += key_data
494
+ else:
495
+ # key used for column selection and output
496
+ results = [
497
+ getattr(obj._gotitem(key, ndim=1), op_name)(how, **kwargs)
498
+ for key, how in func.items()
499
+ ]
500
+ keys = list(func.keys())
501
+
502
+ return keys, results
503
+
504
+ def wrap_results_dict_like(
505
+ self,
506
+ selected_obj: Series | DataFrame,
507
+ result_index: list[Hashable],
508
+ result_data: list,
509
+ ):
510
+ from pandas import Index
511
+ from pandas.core.reshape.concat import concat
512
+
513
+ obj = self.obj
514
+
515
+ # Avoid making two isinstance calls in all and any below
516
+ is_ndframe = [isinstance(r, ABCNDFrame) for r in result_data]
517
+
518
+ if all(is_ndframe):
519
+ results = dict(zip(result_index, result_data))
520
+ keys_to_use: Iterable[Hashable]
521
+ keys_to_use = [k for k in result_index if not results[k].empty]
522
+ # Have to check, if at least one DataFrame is not empty.
523
+ keys_to_use = keys_to_use if keys_to_use != [] else result_index
524
+ if selected_obj.ndim == 2:
525
+ # keys are columns, so we can preserve names
526
+ ktu = Index(keys_to_use)
527
+ ktu._set_names(selected_obj.columns.names)
528
+ keys_to_use = ktu
529
+
530
+ axis: AxisInt = 0 if isinstance(obj, ABCSeries) else 1
531
+ result = concat(
532
+ {k: results[k] for k in keys_to_use},
533
+ axis=axis,
534
+ keys=keys_to_use,
535
+ )
536
+ elif any(is_ndframe):
537
+ # There is a mix of NDFrames and scalars
538
+ raise ValueError(
539
+ "cannot perform both aggregation "
540
+ "and transformation operations "
541
+ "simultaneously"
542
+ )
543
+ else:
544
+ from pandas import Series
545
+
546
+ # we have a list of scalars
547
+ # GH 36212 use name only if obj is a series
548
+ if obj.ndim == 1:
549
+ obj = cast("Series", obj)
550
+ name = obj.name
551
+ else:
552
+ name = None
553
+
554
+ result = Series(result_data, index=result_index, name=name)
555
+
556
+ return result
557
+
558
+ def apply_str(self) -> DataFrame | Series:
559
+ """
560
+ Compute apply in case of a string.
561
+
562
+ Returns
563
+ -------
564
+ result: Series or DataFrame
565
+ """
566
+ # Caller is responsible for checking isinstance(self.f, str)
567
+ func = cast(str, self.func)
568
+
569
+ obj = self.obj
570
+
571
+ from pandas.core.groupby.generic import (
572
+ DataFrameGroupBy,
573
+ SeriesGroupBy,
574
+ )
575
+
576
+ # Support for `frame.transform('method')`
577
+ # Some methods (shift, etc.) require the axis argument, others
578
+ # don't, so inspect and insert if necessary.
579
+ method = getattr(obj, func, None)
580
+ if callable(method):
581
+ sig = inspect.getfullargspec(method)
582
+ arg_names = (*sig.args, *sig.kwonlyargs)
583
+ if self.axis != 0 and (
584
+ "axis" not in arg_names or func in ("corrwith", "skew")
585
+ ):
586
+ raise ValueError(f"Operation {func} does not support axis=1")
587
+ if "axis" in arg_names:
588
+ if isinstance(obj, (SeriesGroupBy, DataFrameGroupBy)):
589
+ # Try to avoid FutureWarning for deprecated axis keyword;
590
+ # If self.axis matches the axis we would get by not passing
591
+ # axis, we safely exclude the keyword.
592
+
593
+ default_axis = 0
594
+ if func in ["idxmax", "idxmin"]:
595
+ # DataFrameGroupBy.idxmax, idxmin axis defaults to self.axis,
596
+ # whereas other axis keywords default to 0
597
+ default_axis = self.obj.axis
598
+
599
+ if default_axis != self.axis:
600
+ self.kwargs["axis"] = self.axis
601
+ else:
602
+ self.kwargs["axis"] = self.axis
603
+ return self._apply_str(obj, func, *self.args, **self.kwargs)
604
+
605
+ def apply_list_or_dict_like(self) -> DataFrame | Series:
606
+ """
607
+ Compute apply in case of a list-like or dict-like.
608
+
609
+ Returns
610
+ -------
611
+ result: Series, DataFrame, or None
612
+ Result when self.func is a list-like or dict-like, None otherwise.
613
+ """
614
+
615
+ if self.engine == "numba":
616
+ raise NotImplementedError(
617
+ "The 'numba' engine doesn't support list-like/"
618
+ "dict likes of callables yet."
619
+ )
620
+
621
+ if self.axis == 1 and isinstance(self.obj, ABCDataFrame):
622
+ return self.obj.T.apply(self.func, 0, args=self.args, **self.kwargs).T
623
+
624
+ func = self.func
625
+ kwargs = self.kwargs
626
+
627
+ if is_dict_like(func):
628
+ result = self.agg_or_apply_dict_like(op_name="apply")
629
+ else:
630
+ result = self.agg_or_apply_list_like(op_name="apply")
631
+
632
+ result = reconstruct_and_relabel_result(result, func, **kwargs)
633
+
634
+ return result
635
+
636
+ def normalize_dictlike_arg(
637
+ self, how: str, obj: DataFrame | Series, func: AggFuncTypeDict
638
+ ) -> AggFuncTypeDict:
639
+ """
640
+ Handler for dict-like argument.
641
+
642
+ Ensures that necessary columns exist if obj is a DataFrame, and
643
+ that a nested renamer is not passed. Also normalizes to all lists
644
+ when values consists of a mix of list and non-lists.
645
+ """
646
+ assert how in ("apply", "agg", "transform")
647
+
648
+ # Can't use func.values(); wouldn't work for a Series
649
+ if (
650
+ how == "agg"
651
+ and isinstance(obj, ABCSeries)
652
+ and any(is_list_like(v) for _, v in func.items())
653
+ ) or (any(is_dict_like(v) for _, v in func.items())):
654
+ # GH 15931 - deprecation of renaming keys
655
+ raise SpecificationError("nested renamer is not supported")
656
+
657
+ if obj.ndim != 1:
658
+ # Check for missing columns on a frame
659
+ from pandas import Index
660
+
661
+ cols = Index(list(func.keys())).difference(obj.columns, sort=True)
662
+ if len(cols) > 0:
663
+ raise KeyError(f"Column(s) {list(cols)} do not exist")
664
+
665
+ aggregator_types = (list, tuple, dict)
666
+
667
+ # if we have a dict of any non-scalars
668
+ # eg. {'A' : ['mean']}, normalize all to
669
+ # be list-likes
670
+ # Cannot use func.values() because arg may be a Series
671
+ if any(isinstance(x, aggregator_types) for _, x in func.items()):
672
+ new_func: AggFuncTypeDict = {}
673
+ for k, v in func.items():
674
+ if not isinstance(v, aggregator_types):
675
+ new_func[k] = [v]
676
+ else:
677
+ new_func[k] = v
678
+ func = new_func
679
+ return func
680
+
681
+ def _apply_str(self, obj, func: str, *args, **kwargs):
682
+ """
683
+ if arg is a string, then try to operate on it:
684
+ - try to find a function (or attribute) on obj
685
+ - try to find a numpy function
686
+ - raise
687
+ """
688
+ assert isinstance(func, str)
689
+
690
+ if hasattr(obj, func):
691
+ f = getattr(obj, func)
692
+ if callable(f):
693
+ return f(*args, **kwargs)
694
+
695
+ # people may aggregate on a non-callable attribute
696
+ # but don't let them think they can pass args to it
697
+ assert len(args) == 0
698
+ assert len([kwarg for kwarg in kwargs if kwarg not in ["axis"]]) == 0
699
+ return f
700
+ elif hasattr(np, func) and hasattr(obj, "__array__"):
701
+ # in particular exclude Window
702
+ f = getattr(np, func)
703
+ return f(obj, *args, **kwargs)
704
+ else:
705
+ msg = f"'{func}' is not a valid function for '{type(obj).__name__}' object"
706
+ raise AttributeError(msg)
707
+
708
+
709
+ class NDFrameApply(Apply):
710
+ """
711
+ Methods shared by FrameApply and SeriesApply but
712
+ not GroupByApply or ResamplerWindowApply
713
+ """
714
+
715
+ obj: DataFrame | Series
716
+
717
+ @property
718
+ def index(self) -> Index:
719
+ return self.obj.index
720
+
721
+ @property
722
+ def agg_axis(self) -> Index:
723
+ return self.obj._get_agg_axis(self.axis)
724
+
725
+ def agg_or_apply_list_like(
726
+ self, op_name: Literal["agg", "apply"]
727
+ ) -> DataFrame | Series:
728
+ obj = self.obj
729
+ kwargs = self.kwargs
730
+
731
+ if op_name == "apply":
732
+ if isinstance(self, FrameApply):
733
+ by_row = self.by_row
734
+
735
+ elif isinstance(self, SeriesApply):
736
+ by_row = "_compat" if self.by_row else False
737
+ else:
738
+ by_row = False
739
+ kwargs = {**kwargs, "by_row": by_row}
740
+
741
+ if getattr(obj, "axis", 0) == 1:
742
+ raise NotImplementedError("axis other than 0 is not supported")
743
+
744
+ keys, results = self.compute_list_like(op_name, obj, kwargs)
745
+ result = self.wrap_results_list_like(keys, results)
746
+ return result
747
+
748
+ def agg_or_apply_dict_like(
749
+ self, op_name: Literal["agg", "apply"]
750
+ ) -> DataFrame | Series:
751
+ assert op_name in ["agg", "apply"]
752
+ obj = self.obj
753
+
754
+ kwargs = {}
755
+ if op_name == "apply":
756
+ by_row = "_compat" if self.by_row else False
757
+ kwargs.update({"by_row": by_row})
758
+
759
+ if getattr(obj, "axis", 0) == 1:
760
+ raise NotImplementedError("axis other than 0 is not supported")
761
+
762
+ selection = None
763
+ result_index, result_data = self.compute_dict_like(
764
+ op_name, obj, selection, kwargs
765
+ )
766
+ result = self.wrap_results_dict_like(obj, result_index, result_data)
767
+ return result
768
+
769
+
770
+ class FrameApply(NDFrameApply):
771
+ obj: DataFrame
772
+
773
+ def __init__(
774
+ self,
775
+ obj: AggObjType,
776
+ func: AggFuncType,
777
+ raw: bool,
778
+ result_type: str | None,
779
+ *,
780
+ by_row: Literal[False, "compat"] = False,
781
+ engine: str = "python",
782
+ engine_kwargs: dict[str, bool] | None = None,
783
+ args,
784
+ kwargs,
785
+ ) -> None:
786
+ if by_row is not False and by_row != "compat":
787
+ raise ValueError(f"by_row={by_row} not allowed")
788
+ super().__init__(
789
+ obj,
790
+ func,
791
+ raw,
792
+ result_type,
793
+ by_row=by_row,
794
+ engine=engine,
795
+ engine_kwargs=engine_kwargs,
796
+ args=args,
797
+ kwargs=kwargs,
798
+ )
799
+
800
+ # ---------------------------------------------------------------
801
+ # Abstract Methods
802
+
803
+ @property
804
+ @abc.abstractmethod
805
+ def result_index(self) -> Index:
806
+ pass
807
+
808
+ @property
809
+ @abc.abstractmethod
810
+ def result_columns(self) -> Index:
811
+ pass
812
+
813
+ @property
814
+ @abc.abstractmethod
815
+ def series_generator(self) -> Generator[Series, None, None]:
816
+ pass
817
+
818
+ @staticmethod
819
+ @functools.cache
820
+ @abc.abstractmethod
821
+ def generate_numba_apply_func(
822
+ func, nogil=True, nopython=True, parallel=False
823
+ ) -> Callable[[npt.NDArray, Index, Index], dict[int, Any]]:
824
+ pass
825
+
826
+ @abc.abstractmethod
827
+ def apply_with_numba(self):
828
+ pass
829
+
830
+ def validate_values_for_numba(self):
831
+ # Validate column dtyps all OK
832
+ for colname, dtype in self.obj.dtypes.items():
833
+ if not is_numeric_dtype(dtype):
834
+ raise ValueError(
835
+ f"Column {colname} must have a numeric dtype. "
836
+ f"Found '{dtype}' instead"
837
+ )
838
+ if is_extension_array_dtype(dtype):
839
+ raise ValueError(
840
+ f"Column {colname} is backed by an extension array, "
841
+ f"which is not supported by the numba engine."
842
+ )
843
+
844
+ @abc.abstractmethod
845
+ def wrap_results_for_axis(
846
+ self, results: ResType, res_index: Index
847
+ ) -> DataFrame | Series:
848
+ pass
849
+
850
+ # ---------------------------------------------------------------
851
+
852
+ @property
853
+ def res_columns(self) -> Index:
854
+ return self.result_columns
855
+
856
+ @property
857
+ def columns(self) -> Index:
858
+ return self.obj.columns
859
+
860
+ @cache_readonly
861
+ def values(self):
862
+ return self.obj.values
863
+
864
+ def apply(self) -> DataFrame | Series:
865
+ """compute the results"""
866
+
867
+ # dispatch to handle list-like or dict-like
868
+ if is_list_like(self.func):
869
+ if self.engine == "numba":
870
+ raise NotImplementedError(
871
+ "the 'numba' engine doesn't support lists of callables yet"
872
+ )
873
+ return self.apply_list_or_dict_like()
874
+
875
+ # all empty
876
+ if len(self.columns) == 0 and len(self.index) == 0:
877
+ return self.apply_empty_result()
878
+
879
+ # string dispatch
880
+ if isinstance(self.func, str):
881
+ if self.engine == "numba":
882
+ raise NotImplementedError(
883
+ "the 'numba' engine doesn't support using "
884
+ "a string as the callable function"
885
+ )
886
+ return self.apply_str()
887
+
888
+ # ufunc
889
+ elif isinstance(self.func, np.ufunc):
890
+ if self.engine == "numba":
891
+ raise NotImplementedError(
892
+ "the 'numba' engine doesn't support "
893
+ "using a numpy ufunc as the callable function"
894
+ )
895
+ with np.errstate(all="ignore"):
896
+ results = self.obj._mgr.apply("apply", func=self.func)
897
+ # _constructor will retain self.index and self.columns
898
+ return self.obj._constructor_from_mgr(results, axes=results.axes)
899
+
900
+ # broadcasting
901
+ if self.result_type == "broadcast":
902
+ if self.engine == "numba":
903
+ raise NotImplementedError(
904
+ "the 'numba' engine doesn't support result_type='broadcast'"
905
+ )
906
+ return self.apply_broadcast(self.obj)
907
+
908
+ # one axis empty
909
+ elif not all(self.obj.shape):
910
+ return self.apply_empty_result()
911
+
912
+ # raw
913
+ elif self.raw:
914
+ return self.apply_raw(engine=self.engine, engine_kwargs=self.engine_kwargs)
915
+
916
+ return self.apply_standard()
917
+
918
+ def agg(self):
919
+ obj = self.obj
920
+ axis = self.axis
921
+
922
+ # TODO: Avoid having to change state
923
+ self.obj = self.obj if self.axis == 0 else self.obj.T
924
+ self.axis = 0
925
+
926
+ result = None
927
+ try:
928
+ result = super().agg()
929
+ finally:
930
+ self.obj = obj
931
+ self.axis = axis
932
+
933
+ if axis == 1:
934
+ result = result.T if result is not None else result
935
+
936
+ if result is None:
937
+ result = self.obj.apply(self.func, axis, args=self.args, **self.kwargs)
938
+
939
+ return result
940
+
941
+ def apply_empty_result(self):
942
+ """
943
+ we have an empty result; at least 1 axis is 0
944
+
945
+ we will try to apply the function to an empty
946
+ series in order to see if this is a reduction function
947
+ """
948
+ assert callable(self.func)
949
+
950
+ # we are not asked to reduce or infer reduction
951
+ # so just return a copy of the existing object
952
+ if self.result_type not in ["reduce", None]:
953
+ return self.obj.copy()
954
+
955
+ # we may need to infer
956
+ should_reduce = self.result_type == "reduce"
957
+
958
+ from pandas import Series
959
+
960
+ if not should_reduce:
961
+ try:
962
+ if self.axis == 0:
963
+ r = self.func(
964
+ Series([], dtype=np.float64), *self.args, **self.kwargs
965
+ )
966
+ else:
967
+ r = self.func(
968
+ Series(index=self.columns, dtype=np.float64),
969
+ *self.args,
970
+ **self.kwargs,
971
+ )
972
+ except Exception:
973
+ pass
974
+ else:
975
+ should_reduce = not isinstance(r, Series)
976
+
977
+ if should_reduce:
978
+ if len(self.agg_axis):
979
+ r = self.func(Series([], dtype=np.float64), *self.args, **self.kwargs)
980
+ else:
981
+ r = np.nan
982
+
983
+ return self.obj._constructor_sliced(r, index=self.agg_axis)
984
+ else:
985
+ return self.obj.copy()
986
+
987
+ def apply_raw(self, engine="python", engine_kwargs=None):
988
+ """apply to the values as a numpy array"""
989
+
990
+ def wrap_function(func):
991
+ """
992
+ Wrap user supplied function to work around numpy issue.
993
+
994
+ see https://github.com/numpy/numpy/issues/8352
995
+ """
996
+
997
+ def wrapper(*args, **kwargs):
998
+ result = func(*args, **kwargs)
999
+ if isinstance(result, str):
1000
+ result = np.array(result, dtype=object)
1001
+ return result
1002
+
1003
+ return wrapper
1004
+
1005
+ if engine == "numba":
1006
+ engine_kwargs = {} if engine_kwargs is None else engine_kwargs
1007
+
1008
+ # error: Argument 1 to "__call__" of "_lru_cache_wrapper" has
1009
+ # incompatible type "Callable[..., Any] | str | list[Callable
1010
+ # [..., Any] | str] | dict[Hashable,Callable[..., Any] | str |
1011
+ # list[Callable[..., Any] | str]]"; expected "Hashable"
1012
+ nb_looper = generate_apply_looper(
1013
+ self.func, **engine_kwargs # type: ignore[arg-type]
1014
+ )
1015
+ result = nb_looper(self.values, self.axis)
1016
+ # If we made the result 2-D, squeeze it back to 1-D
1017
+ result = np.squeeze(result)
1018
+ else:
1019
+ result = np.apply_along_axis(
1020
+ wrap_function(self.func),
1021
+ self.axis,
1022
+ self.values,
1023
+ *self.args,
1024
+ **self.kwargs,
1025
+ )
1026
+
1027
+ # TODO: mixed type case
1028
+ if result.ndim == 2:
1029
+ return self.obj._constructor(result, index=self.index, columns=self.columns)
1030
+ else:
1031
+ return self.obj._constructor_sliced(result, index=self.agg_axis)
1032
+
1033
+ def apply_broadcast(self, target: DataFrame) -> DataFrame:
1034
+ assert callable(self.func)
1035
+
1036
+ result_values = np.empty_like(target.values)
1037
+
1038
+ # axis which we want to compare compliance
1039
+ result_compare = target.shape[0]
1040
+
1041
+ for i, col in enumerate(target.columns):
1042
+ res = self.func(target[col], *self.args, **self.kwargs)
1043
+ ares = np.asarray(res).ndim
1044
+
1045
+ # must be a scalar or 1d
1046
+ if ares > 1:
1047
+ raise ValueError("too many dims to broadcast")
1048
+ if ares == 1:
1049
+ # must match return dim
1050
+ if result_compare != len(res):
1051
+ raise ValueError("cannot broadcast result")
1052
+
1053
+ result_values[:, i] = res
1054
+
1055
+ # we *always* preserve the original index / columns
1056
+ result = self.obj._constructor(
1057
+ result_values, index=target.index, columns=target.columns
1058
+ )
1059
+ return result
1060
+
1061
+ def apply_standard(self):
1062
+ if self.engine == "python":
1063
+ results, res_index = self.apply_series_generator()
1064
+ else:
1065
+ results, res_index = self.apply_series_numba()
1066
+
1067
+ # wrap results
1068
+ return self.wrap_results(results, res_index)
1069
+
1070
+ def apply_series_generator(self) -> tuple[ResType, Index]:
1071
+ assert callable(self.func)
1072
+
1073
+ series_gen = self.series_generator
1074
+ res_index = self.result_index
1075
+
1076
+ results = {}
1077
+
1078
+ with option_context("mode.chained_assignment", None):
1079
+ for i, v in enumerate(series_gen):
1080
+ # ignore SettingWithCopy here in case the user mutates
1081
+ results[i] = self.func(v, *self.args, **self.kwargs)
1082
+ if isinstance(results[i], ABCSeries):
1083
+ # If we have a view on v, we need to make a copy because
1084
+ # series_generator will swap out the underlying data
1085
+ results[i] = results[i].copy(deep=False)
1086
+
1087
+ return results, res_index
1088
+
1089
+ def apply_series_numba(self):
1090
+ if self.engine_kwargs.get("parallel", False):
1091
+ raise NotImplementedError(
1092
+ "Parallel apply is not supported when raw=False and engine='numba'"
1093
+ )
1094
+ if not self.obj.index.is_unique or not self.columns.is_unique:
1095
+ raise NotImplementedError(
1096
+ "The index/columns must be unique when raw=False and engine='numba'"
1097
+ )
1098
+ self.validate_values_for_numba()
1099
+ results = self.apply_with_numba()
1100
+ return results, self.result_index
1101
+
1102
+ def wrap_results(self, results: ResType, res_index: Index) -> DataFrame | Series:
1103
+ from pandas import Series
1104
+
1105
+ # see if we can infer the results
1106
+ if len(results) > 0 and 0 in results and is_sequence(results[0]):
1107
+ return self.wrap_results_for_axis(results, res_index)
1108
+
1109
+ # dict of scalars
1110
+
1111
+ # the default dtype of an empty Series is `object`, but this
1112
+ # code can be hit by df.mean() where the result should have dtype
1113
+ # float64 even if it's an empty Series.
1114
+ constructor_sliced = self.obj._constructor_sliced
1115
+ if len(results) == 0 and constructor_sliced is Series:
1116
+ result = constructor_sliced(results, dtype=np.float64)
1117
+ else:
1118
+ result = constructor_sliced(results)
1119
+ result.index = res_index
1120
+
1121
+ return result
1122
+
1123
+ def apply_str(self) -> DataFrame | Series:
1124
+ # Caller is responsible for checking isinstance(self.func, str)
1125
+ # TODO: GH#39993 - Avoid special-casing by replacing with lambda
1126
+ if self.func == "size":
1127
+ # Special-cased because DataFrame.size returns a single scalar
1128
+ obj = self.obj
1129
+ value = obj.shape[self.axis]
1130
+ return obj._constructor_sliced(value, index=self.agg_axis)
1131
+ return super().apply_str()
1132
+
1133
+
1134
+ class FrameRowApply(FrameApply):
1135
+ axis: AxisInt = 0
1136
+
1137
+ @property
1138
+ def series_generator(self) -> Generator[Series, None, None]:
1139
+ return (self.obj._ixs(i, axis=1) for i in range(len(self.columns)))
1140
+
1141
+ @staticmethod
1142
+ @functools.cache
1143
+ def generate_numba_apply_func(
1144
+ func, nogil=True, nopython=True, parallel=False
1145
+ ) -> Callable[[npt.NDArray, Index, Index], dict[int, Any]]:
1146
+ numba = import_optional_dependency("numba")
1147
+ from pandas import Series
1148
+
1149
+ # Import helper from extensions to cast string object -> np strings
1150
+ # Note: This also has the side effect of loading our numba extensions
1151
+ from pandas.core._numba.extensions import maybe_cast_str
1152
+
1153
+ jitted_udf = numba.extending.register_jitable(func)
1154
+
1155
+ # Currently the parallel argument doesn't get passed through here
1156
+ # (it's disabled) since the dicts in numba aren't thread-safe.
1157
+ @numba.jit(nogil=nogil, nopython=nopython, parallel=parallel)
1158
+ def numba_func(values, col_names, df_index):
1159
+ results = {}
1160
+ for j in range(values.shape[1]):
1161
+ # Create the series
1162
+ ser = Series(
1163
+ values[:, j], index=df_index, name=maybe_cast_str(col_names[j])
1164
+ )
1165
+ results[j] = jitted_udf(ser)
1166
+ return results
1167
+
1168
+ return numba_func
1169
+
1170
+ def apply_with_numba(self) -> dict[int, Any]:
1171
+ nb_func = self.generate_numba_apply_func(
1172
+ cast(Callable, self.func), **self.engine_kwargs
1173
+ )
1174
+ from pandas.core._numba.extensions import set_numba_data
1175
+
1176
+ index = self.obj.index
1177
+ if index.dtype == "string":
1178
+ index = index.astype(object)
1179
+
1180
+ columns = self.obj.columns
1181
+ if columns.dtype == "string":
1182
+ columns = columns.astype(object)
1183
+
1184
+ # Convert from numba dict to regular dict
1185
+ # Our isinstance checks in the df constructor don't pass for numbas typed dict
1186
+ with set_numba_data(index) as index, set_numba_data(columns) as columns:
1187
+ res = dict(nb_func(self.values, columns, index))
1188
+ return res
1189
+
1190
+ @property
1191
+ def result_index(self) -> Index:
1192
+ return self.columns
1193
+
1194
+ @property
1195
+ def result_columns(self) -> Index:
1196
+ return self.index
1197
+
1198
+ def wrap_results_for_axis(
1199
+ self, results: ResType, res_index: Index
1200
+ ) -> DataFrame | Series:
1201
+ """return the results for the rows"""
1202
+
1203
+ if self.result_type == "reduce":
1204
+ # e.g. test_apply_dict GH#8735
1205
+ res = self.obj._constructor_sliced(results)
1206
+ res.index = res_index
1207
+ return res
1208
+
1209
+ elif self.result_type is None and all(
1210
+ isinstance(x, dict) for x in results.values()
1211
+ ):
1212
+ # Our operation was a to_dict op e.g.
1213
+ # test_apply_dict GH#8735, test_apply_reduce_to_dict GH#25196 #37544
1214
+ res = self.obj._constructor_sliced(results)
1215
+ res.index = res_index
1216
+ return res
1217
+
1218
+ try:
1219
+ result = self.obj._constructor(data=results)
1220
+ except ValueError as err:
1221
+ if "All arrays must be of the same length" in str(err):
1222
+ # e.g. result = [[2, 3], [1.5], ['foo', 'bar']]
1223
+ # see test_agg_listlike_result GH#29587
1224
+ res = self.obj._constructor_sliced(results)
1225
+ res.index = res_index
1226
+ return res
1227
+ else:
1228
+ raise
1229
+
1230
+ if not isinstance(results[0], ABCSeries):
1231
+ if len(result.index) == len(self.res_columns):
1232
+ result.index = self.res_columns
1233
+
1234
+ if len(result.columns) == len(res_index):
1235
+ result.columns = res_index
1236
+
1237
+ return result
1238
+
1239
+
1240
+ class FrameColumnApply(FrameApply):
1241
+ axis: AxisInt = 1
1242
+
1243
+ def apply_broadcast(self, target: DataFrame) -> DataFrame:
1244
+ result = super().apply_broadcast(target.T)
1245
+ return result.T
1246
+
1247
+ @property
1248
+ def series_generator(self) -> Generator[Series, None, None]:
1249
+ values = self.values
1250
+ values = ensure_wrapped_if_datetimelike(values)
1251
+ assert len(values) > 0
1252
+
1253
+ # We create one Series object, and will swap out the data inside
1254
+ # of it. Kids: don't do this at home.
1255
+ ser = self.obj._ixs(0, axis=0)
1256
+ mgr = ser._mgr
1257
+
1258
+ is_view = mgr.blocks[0].refs.has_reference() # type: ignore[union-attr]
1259
+
1260
+ if isinstance(ser.dtype, ExtensionDtype):
1261
+ # values will be incorrect for this block
1262
+ # TODO(EA2D): special case would be unnecessary with 2D EAs
1263
+ obj = self.obj
1264
+ for i in range(len(obj)):
1265
+ yield obj._ixs(i, axis=0)
1266
+
1267
+ else:
1268
+ for arr, name in zip(values, self.index):
1269
+ # GH#35462 re-pin mgr in case setitem changed it
1270
+ ser._mgr = mgr
1271
+ mgr.set_values(arr)
1272
+ object.__setattr__(ser, "_name", name)
1273
+ if not is_view:
1274
+ # In apply_series_generator we store the a shallow copy of the
1275
+ # result, which potentially increases the ref count of this reused
1276
+ # `ser` object (depending on the result of the applied function)
1277
+ # -> if that happened and `ser` is already a copy, then we reset
1278
+ # the refs here to avoid triggering a unnecessary CoW inside the
1279
+ # applied function (https://github.com/pandas-dev/pandas/pull/56212)
1280
+ mgr.blocks[0].refs = BlockValuesRefs(mgr.blocks[0]) # type: ignore[union-attr]
1281
+ yield ser
1282
+
1283
+ @staticmethod
1284
+ @functools.cache
1285
+ def generate_numba_apply_func(
1286
+ func, nogil=True, nopython=True, parallel=False
1287
+ ) -> Callable[[npt.NDArray, Index, Index], dict[int, Any]]:
1288
+ numba = import_optional_dependency("numba")
1289
+ from pandas import Series
1290
+ from pandas.core._numba.extensions import maybe_cast_str
1291
+
1292
+ jitted_udf = numba.extending.register_jitable(func)
1293
+
1294
+ @numba.jit(nogil=nogil, nopython=nopython, parallel=parallel)
1295
+ def numba_func(values, col_names_index, index):
1296
+ results = {}
1297
+ # Currently the parallel argument doesn't get passed through here
1298
+ # (it's disabled) since the dicts in numba aren't thread-safe.
1299
+ for i in range(values.shape[0]):
1300
+ # Create the series
1301
+ # TODO: values corrupted without the copy
1302
+ ser = Series(
1303
+ values[i].copy(),
1304
+ index=col_names_index,
1305
+ name=maybe_cast_str(index[i]),
1306
+ )
1307
+ results[i] = jitted_udf(ser)
1308
+
1309
+ return results
1310
+
1311
+ return numba_func
1312
+
1313
+ def apply_with_numba(self) -> dict[int, Any]:
1314
+ nb_func = self.generate_numba_apply_func(
1315
+ cast(Callable, self.func), **self.engine_kwargs
1316
+ )
1317
+
1318
+ from pandas.core._numba.extensions import set_numba_data
1319
+
1320
+ # Convert from numba dict to regular dict
1321
+ # Our isinstance checks in the df constructor don't pass for numbas typed dict
1322
+ with set_numba_data(self.obj.index) as index, set_numba_data(
1323
+ self.columns
1324
+ ) as columns:
1325
+ res = dict(nb_func(self.values, columns, index))
1326
+
1327
+ return res
1328
+
1329
+ @property
1330
+ def result_index(self) -> Index:
1331
+ return self.index
1332
+
1333
+ @property
1334
+ def result_columns(self) -> Index:
1335
+ return self.columns
1336
+
1337
+ def wrap_results_for_axis(
1338
+ self, results: ResType, res_index: Index
1339
+ ) -> DataFrame | Series:
1340
+ """return the results for the columns"""
1341
+ result: DataFrame | Series
1342
+
1343
+ # we have requested to expand
1344
+ if self.result_type == "expand":
1345
+ result = self.infer_to_same_shape(results, res_index)
1346
+
1347
+ # we have a non-series and don't want inference
1348
+ elif not isinstance(results[0], ABCSeries):
1349
+ result = self.obj._constructor_sliced(results)
1350
+ result.index = res_index
1351
+
1352
+ # we may want to infer results
1353
+ else:
1354
+ result = self.infer_to_same_shape(results, res_index)
1355
+
1356
+ return result
1357
+
1358
+ def infer_to_same_shape(self, results: ResType, res_index: Index) -> DataFrame:
1359
+ """infer the results to the same shape as the input object"""
1360
+ result = self.obj._constructor(data=results)
1361
+ result = result.T
1362
+
1363
+ # set the index
1364
+ result.index = res_index
1365
+
1366
+ # infer dtypes
1367
+ result = result.infer_objects(copy=False)
1368
+
1369
+ return result
1370
+
1371
+
1372
+ class SeriesApply(NDFrameApply):
1373
+ obj: Series
1374
+ axis: AxisInt = 0
1375
+ by_row: Literal[False, "compat", "_compat"] # only relevant for apply()
1376
+
1377
+ def __init__(
1378
+ self,
1379
+ obj: Series,
1380
+ func: AggFuncType,
1381
+ *,
1382
+ convert_dtype: bool | lib.NoDefault = lib.no_default,
1383
+ by_row: Literal[False, "compat", "_compat"] = "compat",
1384
+ args,
1385
+ kwargs,
1386
+ ) -> None:
1387
+ if convert_dtype is lib.no_default:
1388
+ convert_dtype = True
1389
+ else:
1390
+ warnings.warn(
1391
+ "the convert_dtype parameter is deprecated and will be removed in a "
1392
+ "future version. Do ``ser.astype(object).apply()`` "
1393
+ "instead if you want ``convert_dtype=False``.",
1394
+ FutureWarning,
1395
+ stacklevel=find_stack_level(),
1396
+ )
1397
+ self.convert_dtype = convert_dtype
1398
+
1399
+ super().__init__(
1400
+ obj,
1401
+ func,
1402
+ raw=False,
1403
+ result_type=None,
1404
+ by_row=by_row,
1405
+ args=args,
1406
+ kwargs=kwargs,
1407
+ )
1408
+
1409
+ def apply(self) -> DataFrame | Series:
1410
+ obj = self.obj
1411
+
1412
+ if len(obj) == 0:
1413
+ return self.apply_empty_result()
1414
+
1415
+ # dispatch to handle list-like or dict-like
1416
+ if is_list_like(self.func):
1417
+ return self.apply_list_or_dict_like()
1418
+
1419
+ if isinstance(self.func, str):
1420
+ # if we are a string, try to dispatch
1421
+ return self.apply_str()
1422
+
1423
+ if self.by_row == "_compat":
1424
+ return self.apply_compat()
1425
+
1426
+ # self.func is Callable
1427
+ return self.apply_standard()
1428
+
1429
+ def agg(self):
1430
+ result = super().agg()
1431
+ if result is None:
1432
+ obj = self.obj
1433
+ func = self.func
1434
+ # string, list-like, and dict-like are entirely handled in super
1435
+ assert callable(func)
1436
+
1437
+ # GH53325: The setup below is just to keep current behavior while emitting a
1438
+ # deprecation message. In the future this will all be replaced with a simple
1439
+ # `result = f(self.obj, *self.args, **self.kwargs)`.
1440
+ try:
1441
+ result = obj.apply(func, args=self.args, **self.kwargs)
1442
+ except (ValueError, AttributeError, TypeError):
1443
+ result = func(obj, *self.args, **self.kwargs)
1444
+ else:
1445
+ msg = (
1446
+ f"using {func} in {type(obj).__name__}.agg cannot aggregate and "
1447
+ f"has been deprecated. Use {type(obj).__name__}.transform to "
1448
+ f"keep behavior unchanged."
1449
+ )
1450
+ warnings.warn(msg, FutureWarning, stacklevel=find_stack_level())
1451
+
1452
+ return result
1453
+
1454
+ def apply_empty_result(self) -> Series:
1455
+ obj = self.obj
1456
+ return obj._constructor(dtype=obj.dtype, index=obj.index).__finalize__(
1457
+ obj, method="apply"
1458
+ )
1459
+
1460
+ def apply_compat(self):
1461
+ """compat apply method for funcs in listlikes and dictlikes.
1462
+
1463
+ Used for each callable when giving listlikes and dictlikes of callables to
1464
+ apply. Needed for compatibility with Pandas < v2.1.
1465
+
1466
+ .. versionadded:: 2.1.0
1467
+ """
1468
+ obj = self.obj
1469
+ func = self.func
1470
+
1471
+ if callable(func):
1472
+ f = com.get_cython_func(func)
1473
+ if f and not self.args and not self.kwargs:
1474
+ return obj.apply(func, by_row=False)
1475
+
1476
+ try:
1477
+ result = obj.apply(func, by_row="compat")
1478
+ except (ValueError, AttributeError, TypeError):
1479
+ result = obj.apply(func, by_row=False)
1480
+ return result
1481
+
1482
+ def apply_standard(self) -> DataFrame | Series:
1483
+ # caller is responsible for ensuring that f is Callable
1484
+ func = cast(Callable, self.func)
1485
+ obj = self.obj
1486
+
1487
+ if isinstance(func, np.ufunc):
1488
+ with np.errstate(all="ignore"):
1489
+ return func(obj, *self.args, **self.kwargs)
1490
+ elif not self.by_row:
1491
+ return func(obj, *self.args, **self.kwargs)
1492
+
1493
+ if self.args or self.kwargs:
1494
+ # _map_values does not support args/kwargs
1495
+ def curried(x):
1496
+ return func(x, *self.args, **self.kwargs)
1497
+
1498
+ else:
1499
+ curried = func
1500
+
1501
+ # row-wise access
1502
+ # apply doesn't have a `na_action` keyword and for backward compat reasons
1503
+ # we need to give `na_action="ignore"` for categorical data.
1504
+ # TODO: remove the `na_action="ignore"` when that default has been changed in
1505
+ # Categorical (GH51645).
1506
+ action = "ignore" if isinstance(obj.dtype, CategoricalDtype) else None
1507
+ mapped = obj._map_values(
1508
+ mapper=curried, na_action=action, convert=self.convert_dtype
1509
+ )
1510
+
1511
+ if len(mapped) and isinstance(mapped[0], ABCSeries):
1512
+ # GH#43986 Need to do list(mapped) in order to get treated as nested
1513
+ # See also GH#25959 regarding EA support
1514
+ return obj._constructor_expanddim(list(mapped), index=obj.index)
1515
+ else:
1516
+ return obj._constructor(mapped, index=obj.index).__finalize__(
1517
+ obj, method="apply"
1518
+ )
1519
+
1520
+
1521
+ class GroupByApply(Apply):
1522
+ obj: GroupBy | Resampler | BaseWindow
1523
+
1524
+ def __init__(
1525
+ self,
1526
+ obj: GroupBy[NDFrameT],
1527
+ func: AggFuncType,
1528
+ *,
1529
+ args,
1530
+ kwargs,
1531
+ ) -> None:
1532
+ kwargs = kwargs.copy()
1533
+ self.axis = obj.obj._get_axis_number(kwargs.get("axis", 0))
1534
+ super().__init__(
1535
+ obj,
1536
+ func,
1537
+ raw=False,
1538
+ result_type=None,
1539
+ args=args,
1540
+ kwargs=kwargs,
1541
+ )
1542
+
1543
+ def apply(self):
1544
+ raise NotImplementedError
1545
+
1546
+ def transform(self):
1547
+ raise NotImplementedError
1548
+
1549
+ def agg_or_apply_list_like(
1550
+ self, op_name: Literal["agg", "apply"]
1551
+ ) -> DataFrame | Series:
1552
+ obj = self.obj
1553
+ kwargs = self.kwargs
1554
+ if op_name == "apply":
1555
+ kwargs = {**kwargs, "by_row": False}
1556
+
1557
+ if getattr(obj, "axis", 0) == 1:
1558
+ raise NotImplementedError("axis other than 0 is not supported")
1559
+
1560
+ if obj._selected_obj.ndim == 1:
1561
+ # For SeriesGroupBy this matches _obj_with_exclusions
1562
+ selected_obj = obj._selected_obj
1563
+ else:
1564
+ selected_obj = obj._obj_with_exclusions
1565
+
1566
+ # Only set as_index=True on groupby objects, not Window or Resample
1567
+ # that inherit from this class.
1568
+ with com.temp_setattr(
1569
+ obj, "as_index", True, condition=hasattr(obj, "as_index")
1570
+ ):
1571
+ keys, results = self.compute_list_like(op_name, selected_obj, kwargs)
1572
+ result = self.wrap_results_list_like(keys, results)
1573
+ return result
1574
+
1575
+ def agg_or_apply_dict_like(
1576
+ self, op_name: Literal["agg", "apply"]
1577
+ ) -> DataFrame | Series:
1578
+ from pandas.core.groupby.generic import (
1579
+ DataFrameGroupBy,
1580
+ SeriesGroupBy,
1581
+ )
1582
+
1583
+ assert op_name in ["agg", "apply"]
1584
+
1585
+ obj = self.obj
1586
+ kwargs = {}
1587
+ if op_name == "apply":
1588
+ by_row = "_compat" if self.by_row else False
1589
+ kwargs.update({"by_row": by_row})
1590
+
1591
+ if getattr(obj, "axis", 0) == 1:
1592
+ raise NotImplementedError("axis other than 0 is not supported")
1593
+
1594
+ selected_obj = obj._selected_obj
1595
+ selection = obj._selection
1596
+
1597
+ is_groupby = isinstance(obj, (DataFrameGroupBy, SeriesGroupBy))
1598
+
1599
+ # Numba Groupby engine/engine-kwargs passthrough
1600
+ if is_groupby:
1601
+ engine = self.kwargs.get("engine", None)
1602
+ engine_kwargs = self.kwargs.get("engine_kwargs", None)
1603
+ kwargs.update({"engine": engine, "engine_kwargs": engine_kwargs})
1604
+
1605
+ with com.temp_setattr(
1606
+ obj, "as_index", True, condition=hasattr(obj, "as_index")
1607
+ ):
1608
+ result_index, result_data = self.compute_dict_like(
1609
+ op_name, selected_obj, selection, kwargs
1610
+ )
1611
+ result = self.wrap_results_dict_like(selected_obj, result_index, result_data)
1612
+ return result
1613
+
1614
+
1615
+ class ResamplerWindowApply(GroupByApply):
1616
+ axis: AxisInt = 0
1617
+ obj: Resampler | BaseWindow
1618
+
1619
+ def __init__(
1620
+ self,
1621
+ obj: Resampler | BaseWindow,
1622
+ func: AggFuncType,
1623
+ *,
1624
+ args,
1625
+ kwargs,
1626
+ ) -> None:
1627
+ super(GroupByApply, self).__init__(
1628
+ obj,
1629
+ func,
1630
+ raw=False,
1631
+ result_type=None,
1632
+ args=args,
1633
+ kwargs=kwargs,
1634
+ )
1635
+
1636
+ def apply(self):
1637
+ raise NotImplementedError
1638
+
1639
+ def transform(self):
1640
+ raise NotImplementedError
1641
+
1642
+
1643
+ def reconstruct_func(
1644
+ func: AggFuncType | None, **kwargs
1645
+ ) -> tuple[bool, AggFuncType, tuple[str, ...] | None, npt.NDArray[np.intp] | None]:
1646
+ """
1647
+ This is the internal function to reconstruct func given if there is relabeling
1648
+ or not and also normalize the keyword to get new order of columns.
1649
+
1650
+ If named aggregation is applied, `func` will be None, and kwargs contains the
1651
+ column and aggregation function information to be parsed;
1652
+ If named aggregation is not applied, `func` is either string (e.g. 'min') or
1653
+ Callable, or list of them (e.g. ['min', np.max]), or the dictionary of column name
1654
+ and str/Callable/list of them (e.g. {'A': 'min'}, or {'A': [np.min, lambda x: x]})
1655
+
1656
+ If relabeling is True, will return relabeling, reconstructed func, column
1657
+ names, and the reconstructed order of columns.
1658
+ If relabeling is False, the columns and order will be None.
1659
+
1660
+ Parameters
1661
+ ----------
1662
+ func: agg function (e.g. 'min' or Callable) or list of agg functions
1663
+ (e.g. ['min', np.max]) or dictionary (e.g. {'A': ['min', np.max]}).
1664
+ **kwargs: dict, kwargs used in is_multi_agg_with_relabel and
1665
+ normalize_keyword_aggregation function for relabelling
1666
+
1667
+ Returns
1668
+ -------
1669
+ relabelling: bool, if there is relabelling or not
1670
+ func: normalized and mangled func
1671
+ columns: tuple of column names
1672
+ order: array of columns indices
1673
+
1674
+ Examples
1675
+ --------
1676
+ >>> reconstruct_func(None, **{"foo": ("col", "min")})
1677
+ (True, defaultdict(<class 'list'>, {'col': ['min']}), ('foo',), array([0]))
1678
+
1679
+ >>> reconstruct_func("min")
1680
+ (False, 'min', None, None)
1681
+ """
1682
+ relabeling = func is None and is_multi_agg_with_relabel(**kwargs)
1683
+ columns: tuple[str, ...] | None = None
1684
+ order: npt.NDArray[np.intp] | None = None
1685
+
1686
+ if not relabeling:
1687
+ if isinstance(func, list) and len(func) > len(set(func)):
1688
+ # GH 28426 will raise error if duplicated function names are used and
1689
+ # there is no reassigned name
1690
+ raise SpecificationError(
1691
+ "Function names must be unique if there is no new column names "
1692
+ "assigned"
1693
+ )
1694
+ if func is None:
1695
+ # nicer error message
1696
+ raise TypeError("Must provide 'func' or tuples of '(column, aggfunc).")
1697
+
1698
+ if relabeling:
1699
+ # error: Incompatible types in assignment (expression has type
1700
+ # "MutableMapping[Hashable, list[Callable[..., Any] | str]]", variable has type
1701
+ # "Callable[..., Any] | str | list[Callable[..., Any] | str] |
1702
+ # MutableMapping[Hashable, Callable[..., Any] | str | list[Callable[..., Any] |
1703
+ # str]] | None")
1704
+ func, columns, order = normalize_keyword_aggregation( # type: ignore[assignment]
1705
+ kwargs
1706
+ )
1707
+ assert func is not None
1708
+
1709
+ return relabeling, func, columns, order
1710
+
1711
+
1712
+ def is_multi_agg_with_relabel(**kwargs) -> bool:
1713
+ """
1714
+ Check whether kwargs passed to .agg look like multi-agg with relabeling.
1715
+
1716
+ Parameters
1717
+ ----------
1718
+ **kwargs : dict
1719
+
1720
+ Returns
1721
+ -------
1722
+ bool
1723
+
1724
+ Examples
1725
+ --------
1726
+ >>> is_multi_agg_with_relabel(a="max")
1727
+ False
1728
+ >>> is_multi_agg_with_relabel(a_max=("a", "max"), a_min=("a", "min"))
1729
+ True
1730
+ >>> is_multi_agg_with_relabel()
1731
+ False
1732
+ """
1733
+ return all(isinstance(v, tuple) and len(v) == 2 for v in kwargs.values()) and (
1734
+ len(kwargs) > 0
1735
+ )
1736
+
1737
+
1738
+ def normalize_keyword_aggregation(
1739
+ kwargs: dict,
1740
+ ) -> tuple[
1741
+ MutableMapping[Hashable, list[AggFuncTypeBase]],
1742
+ tuple[str, ...],
1743
+ npt.NDArray[np.intp],
1744
+ ]:
1745
+ """
1746
+ Normalize user-provided "named aggregation" kwargs.
1747
+ Transforms from the new ``Mapping[str, NamedAgg]`` style kwargs
1748
+ to the old Dict[str, List[scalar]]].
1749
+
1750
+ Parameters
1751
+ ----------
1752
+ kwargs : dict
1753
+
1754
+ Returns
1755
+ -------
1756
+ aggspec : dict
1757
+ The transformed kwargs.
1758
+ columns : tuple[str, ...]
1759
+ The user-provided keys.
1760
+ col_idx_order : List[int]
1761
+ List of columns indices.
1762
+
1763
+ Examples
1764
+ --------
1765
+ >>> normalize_keyword_aggregation({"output": ("input", "sum")})
1766
+ (defaultdict(<class 'list'>, {'input': ['sum']}), ('output',), array([0]))
1767
+ """
1768
+ from pandas.core.indexes.base import Index
1769
+
1770
+ # Normalize the aggregation functions as Mapping[column, List[func]],
1771
+ # process normally, then fixup the names.
1772
+ # TODO: aggspec type: typing.Dict[str, List[AggScalar]]
1773
+ aggspec = defaultdict(list)
1774
+ order = []
1775
+ columns, pairs = list(zip(*kwargs.items()))
1776
+
1777
+ for column, aggfunc in pairs:
1778
+ aggspec[column].append(aggfunc)
1779
+ order.append((column, com.get_callable_name(aggfunc) or aggfunc))
1780
+
1781
+ # uniquify aggfunc name if duplicated in order list
1782
+ uniquified_order = _make_unique_kwarg_list(order)
1783
+
1784
+ # GH 25719, due to aggspec will change the order of assigned columns in aggregation
1785
+ # uniquified_aggspec will store uniquified order list and will compare it with order
1786
+ # based on index
1787
+ aggspec_order = [
1788
+ (column, com.get_callable_name(aggfunc) or aggfunc)
1789
+ for column, aggfuncs in aggspec.items()
1790
+ for aggfunc in aggfuncs
1791
+ ]
1792
+ uniquified_aggspec = _make_unique_kwarg_list(aggspec_order)
1793
+
1794
+ # get the new index of columns by comparison
1795
+ col_idx_order = Index(uniquified_aggspec).get_indexer(uniquified_order)
1796
+ return aggspec, columns, col_idx_order
1797
+
1798
+
1799
+ def _make_unique_kwarg_list(
1800
+ seq: Sequence[tuple[Any, Any]]
1801
+ ) -> Sequence[tuple[Any, Any]]:
1802
+ """
1803
+ Uniquify aggfunc name of the pairs in the order list
1804
+
1805
+ Examples:
1806
+ --------
1807
+ >>> kwarg_list = [('a', '<lambda>'), ('a', '<lambda>'), ('b', '<lambda>')]
1808
+ >>> _make_unique_kwarg_list(kwarg_list)
1809
+ [('a', '<lambda>_0'), ('a', '<lambda>_1'), ('b', '<lambda>')]
1810
+ """
1811
+ return [
1812
+ (pair[0], f"{pair[1]}_{seq[:i].count(pair)}") if seq.count(pair) > 1 else pair
1813
+ for i, pair in enumerate(seq)
1814
+ ]
1815
+
1816
+
1817
+ def relabel_result(
1818
+ result: DataFrame | Series,
1819
+ func: dict[str, list[Callable | str]],
1820
+ columns: Iterable[Hashable],
1821
+ order: Iterable[int],
1822
+ ) -> dict[Hashable, Series]:
1823
+ """
1824
+ Internal function to reorder result if relabelling is True for
1825
+ dataframe.agg, and return the reordered result in dict.
1826
+
1827
+ Parameters:
1828
+ ----------
1829
+ result: Result from aggregation
1830
+ func: Dict of (column name, funcs)
1831
+ columns: New columns name for relabelling
1832
+ order: New order for relabelling
1833
+
1834
+ Examples
1835
+ --------
1836
+ >>> from pandas.core.apply import relabel_result
1837
+ >>> result = pd.DataFrame(
1838
+ ... {"A": [np.nan, 2, np.nan], "C": [6, np.nan, np.nan], "B": [np.nan, 4, 2.5]},
1839
+ ... index=["max", "mean", "min"]
1840
+ ... )
1841
+ >>> funcs = {"A": ["max"], "C": ["max"], "B": ["mean", "min"]}
1842
+ >>> columns = ("foo", "aab", "bar", "dat")
1843
+ >>> order = [0, 1, 2, 3]
1844
+ >>> result_in_dict = relabel_result(result, funcs, columns, order)
1845
+ >>> pd.DataFrame(result_in_dict, index=columns)
1846
+ A C B
1847
+ foo 2.0 NaN NaN
1848
+ aab NaN 6.0 NaN
1849
+ bar NaN NaN 4.0
1850
+ dat NaN NaN 2.5
1851
+ """
1852
+ from pandas.core.indexes.base import Index
1853
+
1854
+ reordered_indexes = [
1855
+ pair[0] for pair in sorted(zip(columns, order), key=lambda t: t[1])
1856
+ ]
1857
+ reordered_result_in_dict: dict[Hashable, Series] = {}
1858
+ idx = 0
1859
+
1860
+ reorder_mask = not isinstance(result, ABCSeries) and len(result.columns) > 1
1861
+ for col, fun in func.items():
1862
+ s = result[col].dropna()
1863
+
1864
+ # In the `_aggregate`, the callable names are obtained and used in `result`, and
1865
+ # these names are ordered alphabetically. e.g.
1866
+ # C2 C1
1867
+ # <lambda> 1 NaN
1868
+ # amax NaN 4.0
1869
+ # max NaN 4.0
1870
+ # sum 18.0 6.0
1871
+ # Therefore, the order of functions for each column could be shuffled
1872
+ # accordingly so need to get the callable name if it is not parsed names, and
1873
+ # reorder the aggregated result for each column.
1874
+ # e.g. if df.agg(c1=("C2", sum), c2=("C2", lambda x: min(x))), correct order is
1875
+ # [sum, <lambda>], but in `result`, it will be [<lambda>, sum], and we need to
1876
+ # reorder so that aggregated values map to their functions regarding the order.
1877
+
1878
+ # However there is only one column being used for aggregation, not need to
1879
+ # reorder since the index is not sorted, and keep as is in `funcs`, e.g.
1880
+ # A
1881
+ # min 1.0
1882
+ # mean 1.5
1883
+ # mean 1.5
1884
+ if reorder_mask:
1885
+ fun = [
1886
+ com.get_callable_name(f) if not isinstance(f, str) else f for f in fun
1887
+ ]
1888
+ col_idx_order = Index(s.index).get_indexer(fun)
1889
+ s = s.iloc[col_idx_order]
1890
+
1891
+ # assign the new user-provided "named aggregation" as index names, and reindex
1892
+ # it based on the whole user-provided names.
1893
+ s.index = reordered_indexes[idx : idx + len(fun)]
1894
+ reordered_result_in_dict[col] = s.reindex(columns, copy=False)
1895
+ idx = idx + len(fun)
1896
+ return reordered_result_in_dict
1897
+
1898
+
1899
+ def reconstruct_and_relabel_result(result, func, **kwargs) -> DataFrame | Series:
1900
+ from pandas import DataFrame
1901
+
1902
+ relabeling, func, columns, order = reconstruct_func(func, **kwargs)
1903
+
1904
+ if relabeling:
1905
+ # This is to keep the order to columns occurrence unchanged, and also
1906
+ # keep the order of new columns occurrence unchanged
1907
+
1908
+ # For the return values of reconstruct_func, if relabeling is
1909
+ # False, columns and order will be None.
1910
+ assert columns is not None
1911
+ assert order is not None
1912
+
1913
+ result_in_dict = relabel_result(result, func, columns, order)
1914
+ result = DataFrame(result_in_dict, index=columns)
1915
+
1916
+ return result
1917
+
1918
+
1919
+ # TODO: Can't use, because mypy doesn't like us setting __name__
1920
+ # error: "partial[Any]" has no attribute "__name__"
1921
+ # the type is:
1922
+ # typing.Sequence[Callable[..., ScalarResult]]
1923
+ # -> typing.Sequence[Callable[..., ScalarResult]]:
1924
+
1925
+
1926
+ def _managle_lambda_list(aggfuncs: Sequence[Any]) -> Sequence[Any]:
1927
+ """
1928
+ Possibly mangle a list of aggfuncs.
1929
+
1930
+ Parameters
1931
+ ----------
1932
+ aggfuncs : Sequence
1933
+
1934
+ Returns
1935
+ -------
1936
+ mangled: list-like
1937
+ A new AggSpec sequence, where lambdas have been converted
1938
+ to have unique names.
1939
+
1940
+ Notes
1941
+ -----
1942
+ If just one aggfunc is passed, the name will not be mangled.
1943
+ """
1944
+ if len(aggfuncs) <= 1:
1945
+ # don't mangle for .agg([lambda x: .])
1946
+ return aggfuncs
1947
+ i = 0
1948
+ mangled_aggfuncs = []
1949
+ for aggfunc in aggfuncs:
1950
+ if com.get_callable_name(aggfunc) == "<lambda>":
1951
+ aggfunc = partial(aggfunc)
1952
+ aggfunc.__name__ = f"<lambda_{i}>"
1953
+ i += 1
1954
+ mangled_aggfuncs.append(aggfunc)
1955
+
1956
+ return mangled_aggfuncs
1957
+
1958
+
1959
+ def maybe_mangle_lambdas(agg_spec: Any) -> Any:
1960
+ """
1961
+ Make new lambdas with unique names.
1962
+
1963
+ Parameters
1964
+ ----------
1965
+ agg_spec : Any
1966
+ An argument to GroupBy.agg.
1967
+ Non-dict-like `agg_spec` are pass through as is.
1968
+ For dict-like `agg_spec` a new spec is returned
1969
+ with name-mangled lambdas.
1970
+
1971
+ Returns
1972
+ -------
1973
+ mangled : Any
1974
+ Same type as the input.
1975
+
1976
+ Examples
1977
+ --------
1978
+ >>> maybe_mangle_lambdas('sum')
1979
+ 'sum'
1980
+ >>> maybe_mangle_lambdas([lambda: 1, lambda: 2]) # doctest: +SKIP
1981
+ [<function __main__.<lambda_0>,
1982
+ <function pandas...._make_lambda.<locals>.f(*args, **kwargs)>]
1983
+ """
1984
+ is_dict = is_dict_like(agg_spec)
1985
+ if not (is_dict or is_list_like(agg_spec)):
1986
+ return agg_spec
1987
+ mangled_aggspec = type(agg_spec)() # dict or OrderedDict
1988
+
1989
+ if is_dict:
1990
+ for key, aggfuncs in agg_spec.items():
1991
+ if is_list_like(aggfuncs) and not is_dict_like(aggfuncs):
1992
+ mangled_aggfuncs = _managle_lambda_list(aggfuncs)
1993
+ else:
1994
+ mangled_aggfuncs = aggfuncs
1995
+
1996
+ mangled_aggspec[key] = mangled_aggfuncs
1997
+ else:
1998
+ mangled_aggspec = _managle_lambda_list(agg_spec)
1999
+
2000
+ return mangled_aggspec
2001
+
2002
+
2003
+ def validate_func_kwargs(
2004
+ kwargs: dict,
2005
+ ) -> tuple[list[str], list[str | Callable[..., Any]]]:
2006
+ """
2007
+ Validates types of user-provided "named aggregation" kwargs.
2008
+ `TypeError` is raised if aggfunc is not `str` or callable.
2009
+
2010
+ Parameters
2011
+ ----------
2012
+ kwargs : dict
2013
+
2014
+ Returns
2015
+ -------
2016
+ columns : List[str]
2017
+ List of user-provided keys.
2018
+ func : List[Union[str, callable[...,Any]]]
2019
+ List of user-provided aggfuncs
2020
+
2021
+ Examples
2022
+ --------
2023
+ >>> validate_func_kwargs({'one': 'min', 'two': 'max'})
2024
+ (['one', 'two'], ['min', 'max'])
2025
+ """
2026
+ tuple_given_message = "func is expected but received {} in **kwargs."
2027
+ columns = list(kwargs)
2028
+ func = []
2029
+ for col_func in kwargs.values():
2030
+ if not (isinstance(col_func, str) or callable(col_func)):
2031
+ raise TypeError(tuple_given_message.format(type(col_func).__name__))
2032
+ func.append(col_func)
2033
+ if not columns:
2034
+ no_arg_message = "Must provide 'func' or named aggregation **kwargs."
2035
+ raise TypeError(no_arg_message)
2036
+ return columns, func
2037
+
2038
+
2039
+ def include_axis(op_name: Literal["agg", "apply"], colg: Series | DataFrame) -> bool:
2040
+ return isinstance(colg, ABCDataFrame) or (
2041
+ isinstance(colg, ABCSeries) and op_name == "agg"
2042
+ )
2043
+
2044
+
2045
+ def warn_alias_replacement(
2046
+ obj: AggObjType,
2047
+ func: Callable,
2048
+ alias: str,
2049
+ ) -> None:
2050
+ if alias.startswith("np."):
2051
+ full_alias = alias
2052
+ else:
2053
+ full_alias = f"{type(obj).__name__}.{alias}"
2054
+ alias = f'"{alias}"'
2055
+ warnings.warn(
2056
+ f"The provided callable {func} is currently using "
2057
+ f"{full_alias}. In a future version of pandas, "
2058
+ f"the provided callable will be used directly. To keep current "
2059
+ f"behavior pass the string {alias} instead.",
2060
+ category=FutureWarning,
2061
+ stacklevel=find_stack_level(),
2062
+ )
lib/python3.12/site-packages/pandas/core/array_algos/__init__.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ core.array_algos is for algorithms that operate on ndarray and ExtensionArray.
3
+ These should:
4
+
5
+ - Assume that any Index, Series, or DataFrame objects have already been unwrapped.
6
+ - Assume that any list arguments have already been cast to ndarray/EA.
7
+ - Not depend on Index, Series, or DataFrame, nor import any of these.
8
+ - May dispatch to ExtensionArray methods, but should not import from core.arrays.
9
+ """
lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (623 Bytes). View file
 
lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/datetimelike_accumulations.cpython-312.pyc ADDED
Binary file (2.99 kB). View file
 
lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/masked_accumulations.cpython-312.pyc ADDED
Binary file (3.66 kB). View file
 
lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/masked_reductions.cpython-312.pyc ADDED
Binary file (6.07 kB). View file
 
lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/putmask.cpython-312.pyc ADDED
Binary file (4.84 kB). View file
 
lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/quantile.cpython-312.pyc ADDED
Binary file (6.67 kB). View file
 
lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/replace.cpython-312.pyc ADDED
Binary file (5.43 kB). View file
 
lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/take.cpython-312.pyc ADDED
Binary file (22.6 kB). View file
 
lib/python3.12/site-packages/pandas/core/array_algos/__pycache__/transforms.cpython-312.pyc ADDED
Binary file (1.55 kB). View file
 
lib/python3.12/site-packages/pandas/core/array_algos/datetimelike_accumulations.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ datetimelke_accumulations.py is for accumulations of datetimelike extension arrays
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import Callable
8
+
9
+ import numpy as np
10
+
11
+ from pandas._libs import iNaT
12
+
13
+ from pandas.core.dtypes.missing import isna
14
+
15
+
16
+ def _cum_func(
17
+ func: Callable,
18
+ values: np.ndarray,
19
+ *,
20
+ skipna: bool = True,
21
+ ):
22
+ """
23
+ Accumulations for 1D datetimelike arrays.
24
+
25
+ Parameters
26
+ ----------
27
+ func : np.cumsum, np.maximum.accumulate, np.minimum.accumulate
28
+ values : np.ndarray
29
+ Numpy array with the values (can be of any dtype that support the
30
+ operation). Values is changed is modified inplace.
31
+ skipna : bool, default True
32
+ Whether to skip NA.
33
+ """
34
+ try:
35
+ fill_value = {
36
+ np.maximum.accumulate: np.iinfo(np.int64).min,
37
+ np.cumsum: 0,
38
+ np.minimum.accumulate: np.iinfo(np.int64).max,
39
+ }[func]
40
+ except KeyError:
41
+ raise ValueError(f"No accumulation for {func} implemented on BaseMaskedArray")
42
+
43
+ mask = isna(values)
44
+ y = values.view("i8")
45
+ y[mask] = fill_value
46
+
47
+ if not skipna:
48
+ mask = np.maximum.accumulate(mask)
49
+
50
+ result = func(y)
51
+ result[mask] = iNaT
52
+
53
+ if values.dtype.kind in "mM":
54
+ return result.view(values.dtype.base)
55
+ return result
56
+
57
+
58
+ def cumsum(values: np.ndarray, *, skipna: bool = True) -> np.ndarray:
59
+ return _cum_func(np.cumsum, values, skipna=skipna)
60
+
61
+
62
+ def cummin(values: np.ndarray, *, skipna: bool = True):
63
+ return _cum_func(np.minimum.accumulate, values, skipna=skipna)
64
+
65
+
66
+ def cummax(values: np.ndarray, *, skipna: bool = True):
67
+ return _cum_func(np.maximum.accumulate, values, skipna=skipna)
lib/python3.12/site-packages/pandas/core/array_algos/masked_accumulations.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ masked_accumulations.py is for accumulation algorithms using a mask-based approach
3
+ for missing values.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from typing import (
9
+ TYPE_CHECKING,
10
+ Callable,
11
+ )
12
+
13
+ import numpy as np
14
+
15
+ if TYPE_CHECKING:
16
+ from pandas._typing import npt
17
+
18
+
19
+ def _cum_func(
20
+ func: Callable,
21
+ values: np.ndarray,
22
+ mask: npt.NDArray[np.bool_],
23
+ *,
24
+ skipna: bool = True,
25
+ ):
26
+ """
27
+ Accumulations for 1D masked array.
28
+
29
+ We will modify values in place to replace NAs with the appropriate fill value.
30
+
31
+ Parameters
32
+ ----------
33
+ func : np.cumsum, np.cumprod, np.maximum.accumulate, np.minimum.accumulate
34
+ values : np.ndarray
35
+ Numpy array with the values (can be of any dtype that support the
36
+ operation).
37
+ mask : np.ndarray
38
+ Boolean numpy array (True values indicate missing values).
39
+ skipna : bool, default True
40
+ Whether to skip NA.
41
+ """
42
+ dtype_info: np.iinfo | np.finfo
43
+ if values.dtype.kind == "f":
44
+ dtype_info = np.finfo(values.dtype.type)
45
+ elif values.dtype.kind in "iu":
46
+ dtype_info = np.iinfo(values.dtype.type)
47
+ elif values.dtype.kind == "b":
48
+ # Max value of bool is 1, but since we are setting into a boolean
49
+ # array, 255 is fine as well. Min value has to be 0 when setting
50
+ # into the boolean array.
51
+ dtype_info = np.iinfo(np.uint8)
52
+ else:
53
+ raise NotImplementedError(
54
+ f"No masked accumulation defined for dtype {values.dtype.type}"
55
+ )
56
+ try:
57
+ fill_value = {
58
+ np.cumprod: 1,
59
+ np.maximum.accumulate: dtype_info.min,
60
+ np.cumsum: 0,
61
+ np.minimum.accumulate: dtype_info.max,
62
+ }[func]
63
+ except KeyError:
64
+ raise NotImplementedError(
65
+ f"No accumulation for {func} implemented on BaseMaskedArray"
66
+ )
67
+
68
+ values[mask] = fill_value
69
+
70
+ if not skipna:
71
+ mask = np.maximum.accumulate(mask)
72
+
73
+ values = func(values)
74
+ return values, mask
75
+
76
+
77
+ def cumsum(values: np.ndarray, mask: npt.NDArray[np.bool_], *, skipna: bool = True):
78
+ return _cum_func(np.cumsum, values, mask, skipna=skipna)
79
+
80
+
81
+ def cumprod(values: np.ndarray, mask: npt.NDArray[np.bool_], *, skipna: bool = True):
82
+ return _cum_func(np.cumprod, values, mask, skipna=skipna)
83
+
84
+
85
+ def cummin(values: np.ndarray, mask: npt.NDArray[np.bool_], *, skipna: bool = True):
86
+ return _cum_func(np.minimum.accumulate, values, mask, skipna=skipna)
87
+
88
+
89
+ def cummax(values: np.ndarray, mask: npt.NDArray[np.bool_], *, skipna: bool = True):
90
+ return _cum_func(np.maximum.accumulate, values, mask, skipna=skipna)
lib/python3.12/site-packages/pandas/core/array_algos/masked_reductions.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ masked_reductions.py is for reduction algorithms using a mask-based approach
3
+ for missing values.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ from typing import (
8
+ TYPE_CHECKING,
9
+ Callable,
10
+ )
11
+ import warnings
12
+
13
+ import numpy as np
14
+
15
+ from pandas._libs import missing as libmissing
16
+
17
+ from pandas.core.nanops import check_below_min_count
18
+
19
+ if TYPE_CHECKING:
20
+ from pandas._typing import (
21
+ AxisInt,
22
+ npt,
23
+ )
24
+
25
+
26
+ def _reductions(
27
+ func: Callable,
28
+ values: np.ndarray,
29
+ mask: npt.NDArray[np.bool_],
30
+ *,
31
+ skipna: bool = True,
32
+ min_count: int = 0,
33
+ axis: AxisInt | None = None,
34
+ **kwargs,
35
+ ):
36
+ """
37
+ Sum, mean or product for 1D masked array.
38
+
39
+ Parameters
40
+ ----------
41
+ func : np.sum or np.prod
42
+ values : np.ndarray
43
+ Numpy array with the values (can be of any dtype that support the
44
+ operation).
45
+ mask : np.ndarray[bool]
46
+ Boolean numpy array (True values indicate missing values).
47
+ skipna : bool, default True
48
+ Whether to skip NA.
49
+ min_count : int, default 0
50
+ The required number of valid values to perform the operation. If fewer than
51
+ ``min_count`` non-NA values are present the result will be NA.
52
+ axis : int, optional, default None
53
+ """
54
+ if not skipna:
55
+ if mask.any() or check_below_min_count(values.shape, None, min_count):
56
+ return libmissing.NA
57
+ else:
58
+ return func(values, axis=axis, **kwargs)
59
+ else:
60
+ if check_below_min_count(values.shape, mask, min_count) and (
61
+ axis is None or values.ndim == 1
62
+ ):
63
+ return libmissing.NA
64
+
65
+ return func(values, where=~mask, axis=axis, **kwargs)
66
+
67
+
68
+ def sum(
69
+ values: np.ndarray,
70
+ mask: npt.NDArray[np.bool_],
71
+ *,
72
+ skipna: bool = True,
73
+ min_count: int = 0,
74
+ axis: AxisInt | None = None,
75
+ ):
76
+ return _reductions(
77
+ np.sum, values=values, mask=mask, skipna=skipna, min_count=min_count, axis=axis
78
+ )
79
+
80
+
81
+ def prod(
82
+ values: np.ndarray,
83
+ mask: npt.NDArray[np.bool_],
84
+ *,
85
+ skipna: bool = True,
86
+ min_count: int = 0,
87
+ axis: AxisInt | None = None,
88
+ ):
89
+ return _reductions(
90
+ np.prod, values=values, mask=mask, skipna=skipna, min_count=min_count, axis=axis
91
+ )
92
+
93
+
94
+ def _minmax(
95
+ func: Callable,
96
+ values: np.ndarray,
97
+ mask: npt.NDArray[np.bool_],
98
+ *,
99
+ skipna: bool = True,
100
+ axis: AxisInt | None = None,
101
+ ):
102
+ """
103
+ Reduction for 1D masked array.
104
+
105
+ Parameters
106
+ ----------
107
+ func : np.min or np.max
108
+ values : np.ndarray
109
+ Numpy array with the values (can be of any dtype that support the
110
+ operation).
111
+ mask : np.ndarray[bool]
112
+ Boolean numpy array (True values indicate missing values).
113
+ skipna : bool, default True
114
+ Whether to skip NA.
115
+ axis : int, optional, default None
116
+ """
117
+ if not skipna:
118
+ if mask.any() or not values.size:
119
+ # min/max with empty array raise in numpy, pandas returns NA
120
+ return libmissing.NA
121
+ else:
122
+ return func(values, axis=axis)
123
+ else:
124
+ subset = values[~mask]
125
+ if subset.size:
126
+ return func(subset, axis=axis)
127
+ else:
128
+ # min/max with empty array raise in numpy, pandas returns NA
129
+ return libmissing.NA
130
+
131
+
132
+ def min(
133
+ values: np.ndarray,
134
+ mask: npt.NDArray[np.bool_],
135
+ *,
136
+ skipna: bool = True,
137
+ axis: AxisInt | None = None,
138
+ ):
139
+ return _minmax(np.min, values=values, mask=mask, skipna=skipna, axis=axis)
140
+
141
+
142
+ def max(
143
+ values: np.ndarray,
144
+ mask: npt.NDArray[np.bool_],
145
+ *,
146
+ skipna: bool = True,
147
+ axis: AxisInt | None = None,
148
+ ):
149
+ return _minmax(np.max, values=values, mask=mask, skipna=skipna, axis=axis)
150
+
151
+
152
+ def mean(
153
+ values: np.ndarray,
154
+ mask: npt.NDArray[np.bool_],
155
+ *,
156
+ skipna: bool = True,
157
+ axis: AxisInt | None = None,
158
+ ):
159
+ if not values.size or mask.all():
160
+ return libmissing.NA
161
+ return _reductions(np.mean, values=values, mask=mask, skipna=skipna, axis=axis)
162
+
163
+
164
+ def var(
165
+ values: np.ndarray,
166
+ mask: npt.NDArray[np.bool_],
167
+ *,
168
+ skipna: bool = True,
169
+ axis: AxisInt | None = None,
170
+ ddof: int = 1,
171
+ ):
172
+ if not values.size or mask.all():
173
+ return libmissing.NA
174
+
175
+ with warnings.catch_warnings():
176
+ warnings.simplefilter("ignore", RuntimeWarning)
177
+ return _reductions(
178
+ np.var, values=values, mask=mask, skipna=skipna, axis=axis, ddof=ddof
179
+ )
180
+
181
+
182
+ def std(
183
+ values: np.ndarray,
184
+ mask: npt.NDArray[np.bool_],
185
+ *,
186
+ skipna: bool = True,
187
+ axis: AxisInt | None = None,
188
+ ddof: int = 1,
189
+ ):
190
+ if not values.size or mask.all():
191
+ return libmissing.NA
192
+
193
+ with warnings.catch_warnings():
194
+ warnings.simplefilter("ignore", RuntimeWarning)
195
+ return _reductions(
196
+ np.std, values=values, mask=mask, skipna=skipna, axis=axis, ddof=ddof
197
+ )