Use numpy.median(array, axis=…) or pandas Series.median(); ndarray has no .median(), so arr.median() triggers this AttributeError.
Seeing this crash mid-analysis feels annoying. The good news: the fix is straightforward once you know where median actually lives in the API. NumPy puts median in the module namespace, not on ndarray objects. That’s why np.median(arr) works and arr.median() fails with AttributeError: ‘NumPy NdArray’ object has no attribute ‘median’. The docs spell out the call shape and options, including axis and keepdims.
Why You See This Error
NumPy arrays expose many methods, yet not every statistic sits there. Median is implemented as a function in the NumPy module, together with related tools like nanmedian and masked-array helpers. So a direct method call on an ndarray raises the attribute message. A classic traceback from this mix-up shows up across Q&A threads and teaching notes, which point users back to np.median.
Quick check: run np.median(your_array). If you need a per-column or per-row result, add axis. The function supports axis=None for a single value, or an integer axis for grouped results, plus keepdims=True to retain shape for downstream math. The reference describes these parameters and edge cases.
import numpy as np
arr = np.array([[1, 9, 3],
[7, 5, 2]])
np.median(arr) # 4.0 (flattened)
np.median(arr, axis=0) # array([4., 7., 2.5])
np.median(arr, axis=1) # array([3., 5.])
Correct Ways To Get The Median
Pick the approach that fits your data. The core call uses np.median. When NaN values appear, reach for np.nanmedian, which ignores NaN during the calculation. If you work with masked arrays, use np.ma.median. These functions share familiar arguments, so swapping is painless.
Plain Arrays
m = np.median(arr, axis=None, keepdims=False)
This returns a scalar for the whole array or a 1-D result along the chosen axis. The docs list how multiple axes get flattened before computing the statistic.
Ignore NaN Values
m = np.nanmedian(arr, axis=0, keepdims=True)
The function skips NaN entries and returns the median of the remaining values. Handy when data imports bring in missing entries as NaN.
Masked Arrays
mx = np.ma.array([1, 2, 3, 999], mask=[0, 0, 0, 1])
m = np.ma.median(mx)
Masked elements drop out of the computation, which keeps results clean in pipelines that mark sentinel values.
Fixes For Common Setups
Different projects hit this error in different places. Use the swap that matches your stack to stop the crash and keep results stable.
- Swap The Call Site — Replace
arr.median()withnp.median(arr). Addaxis=...if you need per-row or per-column output. - Handle NaN First — Use
np.nanmedian(arr)when inputs include missing values. This avoids manual cleanup and keeps the code short. - Use Pandas When You Have A Series — A
pandas.Seriesdoes expose.median(). If your object truly is a Series, keep that call; if it is an ndarray, call the NumPy function. - Retain Shape For Broadcasting — Pass
keepdims=Trueso the output aligns with later vectorized steps without extra reshapes. - Mind The Pattern — Many AttributeErrors in this area stem from calling module functions as if they were instance methods, such as
nan_to_numorappend. Call them on the module:np.nan_to_num(x),np.append(x, v).
Safe Patterns For Axes And Shapes
Median across the wrong axis yields odd shapes. A small table keeps the intent clear during a refactor.
| Goal | Call | Result Shape |
|---|---|---|
| Single value from whole array | np.median(a) |
() scalar |
| Column-wise on 2-D | np.median(a, axis=0) |
(n_cols,) |
| Row-wise with broadcast-friendly dims | np.median(a, axis=1, keepdims=True) |
(n_rows, 1) |
The reference explains how flattening works when you pass a sequence of axes, and how keepdims preserves dimensions for later math.
Small Sample With NaN
a = np.array([[1.0, np.nan, 5.0],
[2.0, 3.0, 4.0]])
np.nanmedian(a) # 3.0
np.nanmedian(a, axis=0) # array([1.5, 3. , 4.5])
np.nanmedian(a, axis=1) # array([3., 3.])
The function ignores NaN and computes the center from the valid numbers. The API mirrors np.median, which keeps your call sites consistent.
AttributeError: ‘NumPy NdArray’ Object Has No Attribute ‘Median’ — Real Code Fixes
This section shows direct swaps that clear the error while keeping results intact. Each swap keeps naming simple and avoids surprise shape changes.
Replace A Direct Method Call
# before
m = arr.median()
# after
m = np.median(arr)
Use the function from the NumPy namespace. The doc page lists the full signature.
Compute Across An Axis
# median of each column
col_m = np.median(arr, axis=0)
# median of each row
row_m = np.median(arr, axis=1)
Pick the axis that matches your grouping. Axis 0 walks rows and returns one value per column. Axis 1 walks columns and returns one value per row.
Skip Missing Values
m = np.nanmedian(arr, axis=0)
When datasets carry NaN, this call avoids a pre-clean step and yields the expected center.
Work With A Masked Array
mx = np.ma.masked_equal(arr, 9999)
m = np.ma.median(mx)
Masked entries drop out, which keeps downstream math steady.
Leaning On A Series
import pandas as pd
s = pd.Series([1, 2, 3, 4, 5])
m = s.median() # Series supports .median()
Pandas objects expose .median(), so code that once worked on a Series will fail after converting to an ndarray. Confirm your object type before calling methods. If it’s a NumPy array, prefer the NumPy function.
When Median Lives In Pandas, Not NumPy
Many pipelines start in pandas, then jump to NumPy for speed or scikit-learn steps. During that jump, a Series turns into an ndarray via .to_numpy() or .values. A subsequent .median() then breaks. Two clean fixes exist: keep the Series until you finish the reduction, or call the NumPy function after conversion.
- Stay In Series — Compute
series.median()before converting to a NumPy array for modeling. This keeps index alignment and dtype rules from pandas while you reduce. - Convert Then Use NumPy — Convert to an array, then call
np.median. This mirrors the function-first pattern used across NumPy’s stats.
# option 1
m1 = df["score"].median()
# option 2
a = df["score"].to_numpy()
m2 = np.median(a)
Shape-Safe Broadcast Back To A DataFrame
a = df.to_numpy()
med = np.median(a, axis=0, keepdims=True)
df_centered = df - med # pairs by column without extra reshape
Using keepdims=True returns a row that aligns with a 2-D frame, which avoids extra plumbing. The reference details shape behavior for these flags.
Practical Debugging Checklist
When a pipeline throws this attribute message, run through a short list. Each step removes a common pitfall fast.
- Confirm The Type — Print
type(obj). If it’snumpy.ndarray, call the function; if it’s a Series, the method call is fine. - Call The Right API — Swap
obj.median()fornp.median(obj). Usenp.nanmedianwhen inputs contain NaN. - Set The Axis — Decide if you want one value, per column, or per row. Pass
axisto match that plan. - Preserve Dimensions — Add
keepdims=Trueif the next step expects a row or column vector. - Scan For Similar Mistakes — If another call reads like an instance method but lives on the module, fix that pattern too. Threads catalog this frequent cause across helpers like
nan_to_num.
Reference Snippets You Can Drop In
Use these small pieces as building blocks. Each one avoids the attribute trap and keeps shapes predictable.
Column Medians Then Center
med = np.median(a, axis=0, keepdims=True)
a_centered = a - med
Row Medians For A Robust Score
row_med = np.median(a, axis=1)
score = np.abs(a - row_med[:, None]).mean()
Ignore NaN In A Single Pass
clean_med = np.nanmedian(a, axis=None)
Each call mirrors the signature in the docs. Keep these patterns near any stats block and you avoid the attribute message altogether. The documentation pages remain the source of truth for arguments and return shapes.
Lastly, note that other array libraries mirror this split between functions and methods. If you port code to JAX, you still call jax.numpy.nanmedian rather than a method on an array object. Knowing the pattern once saves time across stacks.
