Skip to content

Commit 19f0095

Browse files
authored
REF: combine isnaobj+isnaobj_old (#44505)
1 parent 367d3f6 commit 19f0095

File tree

6 files changed

+36
-134
lines changed

6 files changed

+36
-134
lines changed

pandas/_libs/missing.pxd

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ from numpy cimport (
66

77
cpdef bint is_matching_na(object left, object right, bint nan_matches_none=*)
88

9-
cpdef bint checknull(object val)
9+
cpdef bint checknull(object val, bint inf_as_na=*)
1010
cpdef bint checknull_old(object val)
11-
cpdef ndarray[uint8_t] isnaobj(ndarray arr)
11+
cpdef ndarray[uint8_t] isnaobj(ndarray arr, bint inf_as_na=*)
1212

1313
cdef bint is_null_datetime64(v)
1414
cdef bint is_null_timedelta64(v)

pandas/_libs/missing.pyx

+11-123
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ cpdef bint is_matching_na(object left, object right, bint nan_matches_none=False
9999
return False
100100

101101

102-
cpdef bint checknull(object val):
102+
cpdef bint checknull(object val, bint inf_as_na=False):
103103
"""
104104
Return boolean describing of the input is NA-like, defined here as any
105105
of:
@@ -114,19 +114,16 @@ cpdef bint checknull(object val):
114114
Parameters
115115
----------
116116
val : object
117+
inf_as_na : bool, default False
118+
Whether to treat INF and -INF as NA values.
117119
118120
Returns
119121
-------
120122
bool
121-
122-
Notes
123-
-----
124-
The difference between `checknull` and `checknull_old` is that `checknull`
125-
does *not* consider INF or NEGINF to be NA.
126123
"""
127124
return (
128125
val is C_NA
129-
or is_null_datetimelike(val, inat_is_null=False)
126+
or is_null_datetimelike(val, inat_is_null=False, inf_as_na=inf_as_na)
130127
or is_decimal_na(val)
131128
)
132129

@@ -139,42 +136,12 @@ cdef inline bint is_decimal_na(object val):
139136

140137

141138
cpdef bint checknull_old(object val):
142-
"""
143-
Return boolean describing of the input is NA-like, defined here as any
144-
of:
145-
- None
146-
- nan
147-
- INF
148-
- NEGINF
149-
- NaT
150-
- np.datetime64 representation of NaT
151-
- np.timedelta64 representation of NaT
152-
- NA
153-
- Decimal("NaN")
154-
155-
Parameters
156-
----------
157-
val : object
158-
159-
Returns
160-
-------
161-
result : bool
162-
163-
Notes
164-
-----
165-
The difference between `checknull` and `checknull_old` is that `checknull`
166-
does *not* consider INF or NEGINF to be NA.
167-
"""
168-
if checknull(val):
169-
return True
170-
elif util.is_float_object(val) or util.is_complex_object(val):
171-
return val == INF or val == NEGINF
172-
return False
139+
return checknull(val, inf_as_na=True)
173140

174141

175142
@cython.wraparound(False)
176143
@cython.boundscheck(False)
177-
cpdef ndarray[uint8_t] isnaobj(ndarray arr):
144+
cpdef ndarray[uint8_t] isnaobj(ndarray arr, bint inf_as_na=False):
178145
"""
179146
Return boolean mask denoting which elements of a 1-D array are na-like,
180147
according to the criteria defined in `checknull`:
@@ -205,53 +172,19 @@ cpdef ndarray[uint8_t] isnaobj(ndarray arr):
205172
result = np.empty(n, dtype=np.uint8)
206173
for i in range(n):
207174
val = arr[i]
208-
result[i] = checknull(val)
175+
result[i] = checknull(val, inf_as_na=inf_as_na)
209176
return result.view(np.bool_)
210177

211178

212179
@cython.wraparound(False)
213180
@cython.boundscheck(False)
214181
def isnaobj_old(arr: ndarray) -> ndarray:
215-
"""
216-
Return boolean mask denoting which elements of a 1-D array are na-like,
217-
defined as being any of:
218-
- None
219-
- nan
220-
- INF
221-
- NEGINF
222-
- NaT
223-
- NA
224-
- Decimal("NaN")
225-
226-
Parameters
227-
----------
228-
arr : ndarray
229-
230-
Returns
231-
-------
232-
result : ndarray (dtype=np.bool_)
233-
"""
234-
cdef:
235-
Py_ssize_t i, n
236-
object val
237-
ndarray[uint8_t] result
238-
239-
assert arr.ndim == 1, "'arr' must be 1-D."
240-
241-
n = len(arr)
242-
result = np.zeros(n, dtype=np.uint8)
243-
for i in range(n):
244-
val = arr[i]
245-
result[i] = (
246-
checknull(val)
247-
or util.is_float_object(val) and (val == INF or val == NEGINF)
248-
)
249-
return result.view(np.bool_)
182+
return isnaobj(arr, inf_as_na=True)
250183

251184

252185
@cython.wraparound(False)
253186
@cython.boundscheck(False)
254-
def isnaobj2d(arr: ndarray) -> ndarray:
187+
def isnaobj2d(arr: ndarray, inf_as_na: bool = False) -> ndarray:
255188
"""
256189
Return boolean mask denoting which elements of a 2-D array are na-like,
257190
according to the criteria defined in `checknull`:
@@ -270,11 +203,6 @@ def isnaobj2d(arr: ndarray) -> ndarray:
270203
Returns
271204
-------
272205
result : ndarray (dtype=np.bool_)
273-
274-
Notes
275-
-----
276-
The difference between `isnaobj2d` and `isnaobj2d_old` is that `isnaobj2d`
277-
does *not* consider INF or NEGINF to be NA.
278206
"""
279207
cdef:
280208
Py_ssize_t i, j, n, m
@@ -288,55 +216,15 @@ def isnaobj2d(arr: ndarray) -> ndarray:
288216
for i in range(n):
289217
for j in range(m):
290218
val = arr[i, j]
291-
if checknull(val):
219+
if checknull(val, inf_as_na=inf_as_na):
292220
result[i, j] = 1
293221
return result.view(np.bool_)
294222

295223

296224
@cython.wraparound(False)
297225
@cython.boundscheck(False)
298226
def isnaobj2d_old(arr: ndarray) -> ndarray:
299-
"""
300-
Return boolean mask denoting which elements of a 2-D array are na-like,
301-
according to the criteria defined in `checknull_old`:
302-
- None
303-
- nan
304-
- INF
305-
- NEGINF
306-
- NaT
307-
- np.datetime64 representation of NaT
308-
- np.timedelta64 representation of NaT
309-
- NA
310-
- Decimal("NaN")
311-
312-
Parameters
313-
----------
314-
arr : ndarray
315-
316-
Returns
317-
-------
318-
ndarray (dtype=np.bool_)
319-
320-
Notes
321-
-----
322-
The difference between `isnaobj2d` and `isnaobj2d_old` is that `isnaobj2d`
323-
does *not* consider INF or NEGINF to be NA.
324-
"""
325-
cdef:
326-
Py_ssize_t i, j, n, m
327-
object val
328-
ndarray[uint8_t, ndim=2] result
329-
330-
assert arr.ndim == 2, "'arr' must be 2-D."
331-
332-
n, m = (<object>arr).shape
333-
result = np.zeros((n, m), dtype=np.uint8)
334-
for i in range(n):
335-
for j in range(m):
336-
val = arr[i, j]
337-
if checknull_old(val):
338-
result[i, j] = 1
339-
return result.view(np.bool_)
227+
return isnaobj2d(arr, inf_as_na=True)
340228

341229

342230
def isposinf_scalar(val: object) -> bool:

pandas/_libs/tslibs/nattype.pxd

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ cdef _NaT c_NaT
1818
cdef bint checknull_with_nat(object val)
1919
cdef bint is_dt64nat(object val)
2020
cdef bint is_td64nat(object val)
21-
cpdef bint is_null_datetimelike(object val, bint inat_is_null=*)
21+
cpdef bint is_null_datetimelike(object val, bint inat_is_null=*, bint inf_as_na=*)

pandas/_libs/tslibs/nattype.pyi

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ NaT: NaTType
1212
iNaT: int
1313
nat_strings: set[str]
1414

15-
def is_null_datetimelike(val: object, inat_is_null: bool = ...) -> bool: ...
15+
def is_null_datetimelike(
16+
val: object, inat_is_null: bool = ..., inf_as_na: bool = ...
17+
) -> bool: ...
1618

1719
class NaTType(datetime):
1820
value: np.int64

pandas/_libs/tslibs/nattype.pyx

+17-2
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,7 @@ cdef inline bint checknull_with_nat(object val):
12011201
"""
12021202
return val is None or util.is_nan(val) or val is c_NaT
12031203

1204+
12041205
cdef inline bint is_dt64nat(object val):
12051206
"""
12061207
Is this a np.datetime64 object np.datetime64("NaT").
@@ -1209,6 +1210,7 @@ cdef inline bint is_dt64nat(object val):
12091210
return get_datetime64_value(val) == NPY_NAT
12101211
return False
12111212

1213+
12121214
cdef inline bint is_td64nat(object val):
12131215
"""
12141216
Is this a np.timedelta64 object np.timedelta64("NaT").
@@ -1218,7 +1220,14 @@ cdef inline bint is_td64nat(object val):
12181220
return False
12191221

12201222

1221-
cpdef bint is_null_datetimelike(object val, bint inat_is_null=True):
1223+
cdef:
1224+
cnp.float64_t INF = <cnp.float64_t>np.inf
1225+
cnp.float64_t NEGINF = -INF
1226+
1227+
1228+
cpdef bint is_null_datetimelike(
1229+
object val, bint inat_is_null=True, bint inf_as_na=False
1230+
):
12221231
"""
12231232
Determine if we have a null for a timedelta/datetime (or integer versions).
12241233
@@ -1227,6 +1236,8 @@ cpdef bint is_null_datetimelike(object val, bint inat_is_null=True):
12271236
val : object
12281237
inat_is_null : bool, default True
12291238
Whether to treat integer iNaT value as null
1239+
inf_as_na : bool, default False
1240+
Whether to treat INF or -INF value as null.
12301241
12311242
Returns
12321243
-------
@@ -1237,7 +1248,11 @@ cpdef bint is_null_datetimelike(object val, bint inat_is_null=True):
12371248
elif val is c_NaT:
12381249
return True
12391250
elif util.is_float_object(val) or util.is_complex_object(val):
1240-
return val != val
1251+
if val != val:
1252+
return True
1253+
if inf_as_na:
1254+
return val == INF or val == NEGINF
1255+
return False
12411256
elif util.is_timedelta64_object(val):
12421257
return get_timedelta64_value(val) == NPY_NAT
12431258
elif util.is_datetime64_object(val):

pandas/core/dtypes/missing.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def _isna_array(values: ArrayLike, inf_as_na: bool = False):
242242
if not isinstance(values, np.ndarray):
243243
# i.e. ExtensionArray
244244
if inf_as_na and is_categorical_dtype(dtype):
245-
result = libmissing.isnaobj_old(values.to_numpy())
245+
result = libmissing.isnaobj(values.to_numpy(), inf_as_na=inf_as_na)
246246
else:
247247
result = values.isna()
248248
elif is_string_dtype(dtype):
@@ -268,10 +268,7 @@ def _isna_string_dtype(values: np.ndarray, inf_as_na: bool) -> np.ndarray:
268268
result = np.zeros(values.shape, dtype=bool)
269269
else:
270270
result = np.empty(shape, dtype=bool)
271-
if inf_as_na:
272-
vec = libmissing.isnaobj_old(values.ravel())
273-
else:
274-
vec = libmissing.isnaobj(values.ravel())
271+
vec = libmissing.isnaobj(values.ravel(), inf_as_na=inf_as_na)
275272

276273
result[...] = vec.reshape(shape)
277274

0 commit comments

Comments
 (0)