Use pandas.isna() on pandas objects and numpy.isnan() or numpy.isnat() on NumPy arrays—.isnull belongs to pandas, not NumPy.
Hit this message while scanning for missing values? The root cause is simple: isnull is a pandas name, but you called it on a plain NumPy array. NumPy arrays do not carry DataFrame methods, so Python raises an attribute error. The fix is to pick the right null checker for the data you hold and the dtype you work with. That small switch removes the crash and keeps your data pipeline clean now.
What The Error Means And Why It Pops Up
Quick check: Check the object on the left side of the dot. If it is a numpy.ndarray, the method isnull does not exist. A DataFrame or Series in pandas exposes isna() and its alias isnull(). A NumPy array expects NumPy ufuncs like np.isnan for floats or np.isnat for datetimes. Pandas also handles None in object arrays, while raw NumPy focuses on NaN and NaT.
In short, the names look similar but live in different libraries. Call pandas functions on pandas objects; call NumPy functions on NumPy arrays. That separation avoids surprises and keeps behavior consistent across projects.
Use The Right Missing-Value Test By Data Type
Pick the function that matches both your container and the underlying dtype. The table gives you a fast map from context to the correct call.
| Context | What To Call | Notes |
|---|---|---|
| Pandas DataFrame / Series | obj.isna() or pd.isna(obj) |
isnull() is an alias of isna(); handles NaN, None, and NaT. |
| NumPy float/complex arrays | np.isnan(arr) |
Element-wise test for NaN values in numeric arrays. |
| NumPy datetime/timedelta arrays | np.isnat(arr) |
Detects missing time values (NaT) element-wise. |
Why this matters: Missing values drive many downstream steps: imputers, model features, and quality checks. A wrong check either drops good rows or keeps bad ones. Getting the null test right at the container level saves time and avoids quiet data drift. Pandas wraps a broad notion of missingness across dtypes, while NumPy gives tight, dtype-specific primitives. Pick based on the surface you need.
Typical stack trace: You will see an AttributeError that names numpy.ndarray and the unknown attribute isnull. The final line points to the code line where the array method call happens. Confirm it by printing type(obj) just before the call.
Data layout clues: If your array came from CSV via pandas, you likely still hold a DataFrame. If it came from image loaders, scikit-learn, or math helpers, you often hold a NumPy array. That origin story often explains which API you should call next.
Map your intent: If you want the broadest notion of missing across numbers, strings, and dates, reach for pandas. If you want speed on pure numeric arrays and precise control, stay with NumPy. Both paths deliver the mask you need; they just draw the boundary in different places.
Datetime nuance: np.isnat focuses on datetime and timedelta dtypes. Pandas will also flag NaT with isna(), which makes mixed operations on time columns easier when you need groupby or resampling later.
Nullable pandas dtypes: The newer Int64, boolean, and string dtypes carry their own NA sentinel while keeping vectorization. isna() works across these as well, which can clean up mixed object columns and keep math fast.
AttributeError: ‘NumPy NdArray’ Object Has No Attribute ‘IsNull’ — Common Causes
Case mismatch: The method is lowercase in pandas. If you write IsNull with a capital I, pandas would still work when you call isnull on a DataFrame, but the attribute path on a NumPy array fails either way.
Lost pandas type: Many helpers return NumPy arrays. A common path is calling values, .to_numpy(), or a scikit-learn splitter, then trying a DataFrame method. At that point you no longer have column labels or pandas methods, so isnull vanishes.
Wrong function for dtype: np.isnan checks for NaN in numeric arrays. It does not accept strings. For datetimes you need np.isnat. For mixed objects, switch to pandas and use isna.
Checking Nulls On A Numpy Ndarray Without Isnull
There are two clean paths when you hold a raw array and want a missing-value mask without calling isnull. First, keep the array and use NumPy ufuncs. Second, wrap it in a pandas object and use the pandas API for richer null rules. Both paths are simple to read, and both avoid the crash that comes with attributeerror: 'numpy ndarray' object has no attribute 'isnull'.
- Stay With NumPy — Call
np.isnanfor floats and complex numbers, ornp.isnatfor time types. These are vectorized across the array and return a boolean mask. - Wrap In Pandas — Create a Series or DataFrame and call
isna(). This route flagsNonein object dtype andNaTin datetimes, which aligns with pandas’ missing-data rules.
Quick, Reliable Fixes You Can Apply Now
- Stay In Pandas When You Need Mixed Null Logic — Keep your data as a DataFrame or Series and call
isna()orisnull(). That handlesNaN,None, andNaTin one line. - Use NumPy Ufuncs On NumPy Arrays — For numeric arrays call
np.isnan(arr). For datetime or timedelta arrays callnp.isnat(arr). Build masks, then slice or fill. - Convert Intentionally — If you must use a pandas method, convert your array:
pd.Series(arr).isna(). For performance, convert back only when needed. - Guard For Objects — If your array holds strings or mixed Python objects, create a Series and run
isna(), or build a mask with a comprehension that treats empty strings separately. - Index With The Mask You Built — Pair your boolean mask with
np.whereor direct boolean indexing to select, fill, or drop values.
Proven Patterns With Short Code Samples
Numeric Arrays: Detect And Fill NaN
import numpy as np
arr = np.array([1.0, np.nan, 3.5, np.nan])
mask = np.isnan(arr) # True where arr is NaN
arr[mask] = 0.0 # replace NaN with 0
Pandas Series And DataFrames: One Call For All Nulls
import pandas as pd
s = pd.Series([1, None, 3, float("nan")])
null_mask = s.isna() # or s.isnull(); alias
clean = s.fillna(0)
Also note: infinite values are not treated as missing by default. You can opt in with pd.options.mode.use_inf_as_na = True when that matches your rules.
Datetime Arrays: Treat NaT Correctly
import numpy as np
dts = np.array(["2024-01-01", "NaT", "2024-03-05"], dtype="datetime64[ns]")
timemask = np.isnat(dts) # True at the NaT slot
After A Train/Test Split: You Now Hold Arrays
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
df = pd.DataFrame({"x":[1.0, np.nan, 3.0, 4.0], "y":[0,1,0,1]})
X_train, X_test, y_train, y_test = train_test_split(df[["x"]], df["y"], random_state=0)
# Beware: many sklearn steps return or expect NumPy arrays.
X_np = X_train.to_numpy()
mask = np.isnan(X_np) # works
# X_np.isnull() # raises AttributeError
That pattern explains why errors that look similar pop up with other methods such as .fillna, .columns, or .index when called on arrays. The fix is the same: call pandas methods on pandas objects, or switch to a NumPy-level alternative.
Groupby With Null Awareness In Pandas
import pandas as pd
import numpy as np
df = pd.DataFrame({
"city": ["A", "A", "B", "B", "B"],
"temp": [21.0, np.nan, 19.5, 18.0, np.nan]
})
mask = df["temp"].isna()
report = {
"null_rate": mask.mean(),
"rows_with_null": int(mask.sum())
}
# Strategy: fill per city with the mean of that city
filled = df.assign(temp=df["temp"].fillna(df.groupby("city")["temp"].transform("mean")))
Why this helps: You keep the check and the policy close together. Anyone scanning the code can see where missing data is found and how it is handled in the same block.
Array Indexing With np.where
import numpy as np
arr = np.array([2.0, np.nan, 5.0, np.nan, 7.5])
mask = np.isnan(arr)
idx = np.where(mask)[0] # positions of NaN
# sample: drop NaN by boolean indexing
clean = arr[~mask]
Readable flow: Build mask, use mask, show the reason in variable names. That pattern keeps intent clear across reviews and notebooks.
Edge Cases, Dtype Pitfalls, And Safer Patterns
None vs np.nan: In pandas, both mark missing entries, with subtle dtype effects. In raw NumPy, None forces dtype=object, which blocks numeric ufuncs like np.isnan. Shift the data into pandas or convert values before the check.
NaN comparisons: By design, np.nan == np.nan is False, so equality checks do not find missing values. Always use np.isnan for floats or isna() in pandas.
Pandas options: Empty strings are not missing, and inf is not missing unless you opt in. Use pd.options.mode.use_inf_as_na = True when you want inf treated as NA during checks.
Masked arrays: NumPy also ships np.ma for masked arithmetic. If your pipeline already uses masked arrays, you can build masks from np.isnan or np.isnat and pass them into a masked view without converting to pandas.
Prevent the error in new code: Add type hints and quick asserts at boundaries: def clean(x: np.ndarray) -> np.ndarray: with assert isinstance(x, np.ndarray). Keep a test that feeds a list, a NumPy array, and a DataFrame to the same function and confirms the branch you intend. Prefer a single conversion point near the start of a pipeline to avoid toggling types line by line.
Troubleshooting checklist:
- Print The Type — Run
type(obj). If you seenumpy.ndarray, move tonp.isnanornp.isnat. If you seepandas.Seriesorpandas.DataFrame, use.isna(). - Inspect Dtypes — Call
arr.dtypeordf.dtypes. Choose the checker that matches the dtype. - Avoid Mixed Objects In NumPy — If
dtype=object, switch to pandas for a cleaner null story. - Build A Mask Once — Store the boolean array from the null check. Reuse it for indexing, filling, or reporting.
- Keep One Library Boundary — Do not bounce back and forth on every line. Convert once, do the work, then convert back.
Reference Notes
The pandas docs list pandas.isnull and DataFrame.isnull as missing-value detectors and state that isnull is an alias of isna. NumPy documents np.isnan for element-wise NaN checks and np.isnat for NaT in datetime or timedelta arrays. These references match the fixes above and explain why the attribute error shows up when you call isnull on an array.
Field sanity: After fixing the check, print a tiny sample of rows that the mask flags. A quick glance catches type slips, such as strings like "nan" or whitespace, before they creep into joins and charts right away.
Finally, the exact error string can help teammates search code history. This page includes the raw text twice: attributeerror: ‘numpy ndarray’ object has no attribute ‘isnull’. That mirrors the message while staying clear about the fix path.
