38
38
is_any_int_dtype ,
39
39
is_bool_dtype ,
40
40
is_complex ,
41
- is_datetime64_any_dtype ,
42
41
is_float ,
43
42
is_float_dtype ,
44
43
is_integer ,
45
- is_integer_dtype ,
46
44
is_numeric_dtype ,
47
45
is_object_dtype ,
48
46
is_scalar ,
49
- is_timedelta64_dtype ,
50
47
needs_i8_conversion ,
51
48
pandas_dtype ,
52
49
)
@@ -161,7 +158,7 @@ def f(
161
158
162
159
def _bn_ok_dtype (dtype : DtypeObj , name : str ) -> bool :
163
160
# Bottleneck chokes on datetime64, PeriodDtype (or and EA)
164
- if not is_object_dtype ( dtype ) and not needs_i8_conversion (dtype ):
161
+ if dtype != object and not needs_i8_conversion (dtype ):
165
162
# GH 42878
166
163
# Bottleneck uses naive summation leading to O(n) loss of precision
167
164
# unlike numpy which implements pairwise summation, which has O(log(n)) loss
@@ -248,7 +245,7 @@ def _maybe_get_mask(
248
245
Optional[np.ndarray[bool]]
249
246
"""
250
247
if mask is None :
251
- if is_bool_dtype ( values .dtype ) or is_integer_dtype ( values . dtype ) :
248
+ if values .dtype . kind in "biu" :
252
249
# Boolean data cannot contain nulls, so signal via mask being None
253
250
return None
254
251
@@ -264,7 +261,7 @@ def _get_values(
264
261
fill_value : Any = None ,
265
262
fill_value_typ : str | None = None ,
266
263
mask : npt .NDArray [np .bool_ ] | None = None ,
267
- ) -> tuple [np .ndarray , npt .NDArray [np .bool_ ] | None , np . dtype , np . dtype , Any ]:
264
+ ) -> tuple [np .ndarray , npt .NDArray [np .bool_ ] | None ]:
268
265
"""
269
266
Utility to get the values view, mask, dtype, dtype_max, and fill_value.
270
267
@@ -294,12 +291,6 @@ def _get_values(
294
291
Potential copy of input value array
295
292
mask : Optional[ndarray[bool]]
296
293
Mask for values, if deemed necessary to compute
297
- dtype : np.dtype
298
- dtype for values
299
- dtype_max : np.dtype
300
- platform independent dtype
301
- fill_value : Any
302
- fill value used
303
294
"""
304
295
# In _get_values is only called from within nanops, and in all cases
305
296
# with scalar fill_value. This guarantee is important for the
@@ -317,31 +308,33 @@ def _get_values(
317
308
values = np .asarray (values .view ("i8" ))
318
309
datetimelike = True
319
310
320
- dtype_ok = _na_ok_dtype (dtype )
311
+ if skipna and (mask is not None ):
312
+ # get our fill value (in case we need to provide an alternative
313
+ # dtype for it)
314
+ fill_value = _get_fill_value (
315
+ dtype , fill_value = fill_value , fill_value_typ = fill_value_typ
316
+ )
321
317
322
- # get our fill value (in case we need to provide an alternative
323
- # dtype for it)
324
- fill_value = _get_fill_value (
325
- dtype , fill_value = fill_value , fill_value_typ = fill_value_typ
326
- )
318
+ if fill_value is not None :
319
+ if mask .any ():
320
+ if datetimelike or _na_ok_dtype (dtype ):
321
+ values = values .copy ()
322
+ np .putmask (values , mask , fill_value )
323
+ else :
324
+ # np.where will promote if needed
325
+ values = np .where (~ mask , values , fill_value )
326
+
327
+ return values , mask
327
328
328
- if skipna and (mask is not None ) and (fill_value is not None ):
329
- if mask .any ():
330
- if dtype_ok or datetimelike :
331
- values = values .copy ()
332
- np .putmask (values , mask , fill_value )
333
- else :
334
- # np.where will promote if needed
335
- values = np .where (~ mask , values , fill_value )
336
329
330
+ def _get_dtype_max (dtype : np .dtype ) -> np .dtype :
337
331
# return a platform independent precision dtype
338
332
dtype_max = dtype
339
- if is_integer_dtype ( dtype ) or is_bool_dtype ( dtype ) :
333
+ if dtype . kind in "biu" :
340
334
dtype_max = np .dtype (np .int64 )
341
- elif is_float_dtype ( dtype ) :
335
+ elif dtype . kind == "f" :
342
336
dtype_max = np .dtype (np .float64 )
343
-
344
- return values , mask , dtype , dtype_max , fill_value
337
+ return dtype_max
345
338
346
339
347
340
def _na_ok_dtype (dtype : DtypeObj ) -> bool :
@@ -355,7 +348,7 @@ def _wrap_results(result, dtype: np.dtype, fill_value=None):
355
348
if result is NaT :
356
349
pass
357
350
358
- elif is_datetime64_any_dtype ( dtype ) :
351
+ elif dtype . kind == "M" :
359
352
if fill_value is None :
360
353
# GH#24293
361
354
fill_value = iNaT
@@ -373,7 +366,7 @@ def _wrap_results(result, dtype: np.dtype, fill_value=None):
373
366
else :
374
367
# If we have float dtype, taking a view will give the wrong result
375
368
result = result .astype (dtype )
376
- elif is_timedelta64_dtype ( dtype ) :
369
+ elif dtype . kind == "m" :
377
370
if not isinstance (result , np .ndarray ):
378
371
if result == fill_value or np .isnan (result ):
379
372
result = np .timedelta64 ("NaT" ).astype (dtype )
@@ -442,7 +435,7 @@ def _na_for_min_count(values: np.ndarray, axis: AxisInt | None) -> Scalar | np.n
442
435
For 2-D values, returns a 1-D array where each element is missing.
443
436
"""
444
437
# we either return np.nan or pd.NaT
445
- if is_numeric_dtype (values ):
438
+ if is_numeric_dtype (values . dtype ):
446
439
values = values .astype ("float64" )
447
440
fill_value = na_value_for_dtype (values .dtype )
448
441
@@ -533,11 +526,11 @@ def nanany(
533
526
stacklevel = find_stack_level (),
534
527
)
535
528
536
- values , _ , _ , _ , _ = _get_values (values , skipna , fill_value = False , mask = mask )
529
+ values , _ = _get_values (values , skipna , fill_value = False , mask = mask )
537
530
538
531
# For object type, any won't necessarily return
539
532
# boolean values (numpy/numpy#4352)
540
- if is_object_dtype ( values ) :
533
+ if values . dtype == object :
541
534
values = values .astype (bool )
542
535
543
536
# error: Incompatible return value type (got "Union[bool_, ndarray]", expected
@@ -588,11 +581,11 @@ def nanall(
588
581
stacklevel = find_stack_level (),
589
582
)
590
583
591
- values , _ , _ , _ , _ = _get_values (values , skipna , fill_value = True , mask = mask )
584
+ values , _ = _get_values (values , skipna , fill_value = True , mask = mask )
592
585
593
586
# For object type, all won't necessarily return
594
587
# boolean values (numpy/numpy#4352)
595
- if is_object_dtype ( values ) :
588
+ if values . dtype == object :
596
589
values = values .astype (bool )
597
590
598
591
# error: Incompatible return value type (got "Union[bool_, ndarray]", expected
@@ -634,13 +627,12 @@ def nansum(
634
627
>>> nanops.nansum(s.values)
635
628
3.0
636
629
"""
637
- values , mask , dtype , dtype_max , _ = _get_values (
638
- values , skipna , fill_value = 0 , mask = mask
639
- )
640
- dtype_sum = dtype_max
641
- if is_float_dtype (dtype ):
630
+ dtype = values .dtype
631
+ values , mask = _get_values (values , skipna , fill_value = 0 , mask = mask )
632
+ dtype_sum = _get_dtype_max (dtype )
633
+ if dtype .kind == "f" :
642
634
dtype_sum = dtype
643
- elif is_timedelta64_dtype ( dtype ) :
635
+ elif dtype . kind == "m" :
644
636
dtype_sum = np .dtype (np .float64 )
645
637
646
638
the_sum = values .sum (axis , dtype = dtype_sum )
@@ -702,18 +694,17 @@ def nanmean(
702
694
>>> nanops.nanmean(s.values)
703
695
1.5
704
696
"""
705
- values , mask , dtype , dtype_max , _ = _get_values (
706
- values , skipna , fill_value = 0 , mask = mask
707
- )
708
- dtype_sum = dtype_max
697
+ dtype = values .dtype
698
+ values , mask = _get_values (values , skipna , fill_value = 0 , mask = mask )
699
+ dtype_sum = _get_dtype_max (dtype )
709
700
dtype_count = np .dtype (np .float64 )
710
701
711
702
# not using needs_i8_conversion because that includes period
712
- if dtype .kind in [ "m" , "M" ] :
703
+ if dtype .kind in "mM" :
713
704
dtype_sum = np .dtype (np .float64 )
714
- elif is_integer_dtype ( dtype ) :
705
+ elif dtype . kind in "iu" :
715
706
dtype_sum = np .dtype (np .float64 )
716
- elif is_float_dtype ( dtype ) :
707
+ elif dtype . kind == "f" :
717
708
dtype_sum = dtype
718
709
dtype_count = dtype
719
710
@@ -774,8 +765,9 @@ def get_median(x, _mask=None):
774
765
res = np .nanmedian (x [_mask ])
775
766
return res
776
767
777
- values , mask , dtype , _ , _ = _get_values (values , skipna , mask = mask , fill_value = 0 )
778
- if not is_float_dtype (values .dtype ):
768
+ dtype = values .dtype
769
+ values , mask = _get_values (values , skipna , mask = mask , fill_value = 0 )
770
+ if values .dtype .kind != "f" :
779
771
try :
780
772
values = values .astype ("f8" )
781
773
except ValueError as err :
@@ -929,7 +921,7 @@ def nanstd(
929
921
values = values .view ("m8[ns]" )
930
922
931
923
orig_dtype = values .dtype
932
- values , mask , _ , _ , _ = _get_values (values , skipna , mask = mask )
924
+ values , mask = _get_values (values , skipna , mask = mask )
933
925
934
926
result = np .sqrt (nanvar (values , axis = axis , skipna = skipna , ddof = ddof , mask = mask ))
935
927
return _wrap_results (result , orig_dtype )
@@ -1051,7 +1043,7 @@ def nansem(
1051
1043
nanvar (values , axis = axis , skipna = skipna , ddof = ddof , mask = mask )
1052
1044
1053
1045
mask = _maybe_get_mask (values , skipna , mask )
1054
- if not is_float_dtype ( values .dtype ) :
1046
+ if values .dtype . kind != "f" :
1055
1047
values = values .astype ("f8" )
1056
1048
1057
1049
if not skipna and mask is not None and mask .any ():
@@ -1073,11 +1065,13 @@ def reduction(
1073
1065
skipna : bool = True ,
1074
1066
mask : npt .NDArray [np .bool_ ] | None = None ,
1075
1067
) -> Dtype :
1076
- values , mask , dtype , dtype_max , fill_value = _get_values (
1068
+ dtype = values .dtype
1069
+ values , mask = _get_values (
1077
1070
values , skipna , fill_value_typ = fill_value_typ , mask = mask
1078
1071
)
1079
1072
1080
1073
if (axis is not None and values .shape [axis ] == 0 ) or values .size == 0 :
1074
+ dtype_max = _get_dtype_max (dtype )
1081
1075
try :
1082
1076
result = getattr (values , meth )(axis , dtype = dtype_max )
1083
1077
result .fill (np .nan )
@@ -1135,7 +1129,7 @@ def nanargmax(
1135
1129
>>> nanops.nanargmax(arr, axis=1)
1136
1130
array([2, 2, 1, 1])
1137
1131
"""
1138
- values , mask , _ , _ , _ = _get_values (values , True , fill_value_typ = "-inf" , mask = mask )
1132
+ values , mask = _get_values (values , True , fill_value_typ = "-inf" , mask = mask )
1139
1133
# error: Need type annotation for 'result'
1140
1134
result = values .argmax (axis ) # type: ignore[var-annotated]
1141
1135
result = _maybe_arg_null_out (result , axis , mask , skipna )
@@ -1181,7 +1175,7 @@ def nanargmin(
1181
1175
>>> nanops.nanargmin(arr, axis=1)
1182
1176
array([0, 0, 1, 1])
1183
1177
"""
1184
- values , mask , _ , _ , _ = _get_values (values , True , fill_value_typ = "+inf" , mask = mask )
1178
+ values , mask = _get_values (values , True , fill_value_typ = "+inf" , mask = mask )
1185
1179
# error: Need type annotation for 'result'
1186
1180
result = values .argmin (axis ) # type: ignore[var-annotated]
1187
1181
result = _maybe_arg_null_out (result , axis , mask , skipna )
@@ -1226,7 +1220,7 @@ def nanskew(
1226
1220
1.7320508075688787
1227
1221
"""
1228
1222
mask = _maybe_get_mask (values , skipna , mask )
1229
- if not is_float_dtype ( values .dtype ) :
1223
+ if values .dtype . kind != "f" :
1230
1224
values = values .astype ("f8" )
1231
1225
count = _get_counts (values .shape , mask , axis )
1232
1226
else :
@@ -1262,7 +1256,7 @@ def nanskew(
1262
1256
result = (count * (count - 1 ) ** 0.5 / (count - 2 )) * (m3 / m2 ** 1.5 )
1263
1257
1264
1258
dtype = values .dtype
1265
- if is_float_dtype ( dtype ) :
1259
+ if dtype . kind == "f" :
1266
1260
result = result .astype (dtype , copy = False )
1267
1261
1268
1262
if isinstance (result , np .ndarray ):
@@ -1314,7 +1308,7 @@ def nankurt(
1314
1308
-1.2892561983471076
1315
1309
"""
1316
1310
mask = _maybe_get_mask (values , skipna , mask )
1317
- if not is_float_dtype ( values .dtype ) :
1311
+ if values .dtype . kind != "f" :
1318
1312
values = values .astype ("f8" )
1319
1313
count = _get_counts (values .shape , mask , axis )
1320
1314
else :
@@ -1363,7 +1357,7 @@ def nankurt(
1363
1357
result = numerator / denominator - adj
1364
1358
1365
1359
dtype = values .dtype
1366
- if is_float_dtype ( dtype ) :
1360
+ if dtype . kind == "f" :
1367
1361
result = result .astype (dtype , copy = False )
1368
1362
1369
1363
if isinstance (result , np .ndarray ):
@@ -1667,9 +1661,9 @@ def nancov(
1667
1661
1668
1662
def _ensure_numeric (x ):
1669
1663
if isinstance (x , np .ndarray ):
1670
- if is_integer_dtype ( x ) or is_bool_dtype ( x ) :
1664
+ if x . dtype . kind in "biu" :
1671
1665
x = x .astype (np .float64 )
1672
- elif is_object_dtype ( x ) :
1666
+ elif x . dtype == object :
1673
1667
try :
1674
1668
x = x .astype (np .complex128 )
1675
1669
except (TypeError , ValueError ):
0 commit comments