pandas-dev/pandas · error · NotImplementedError
> 1 ndim Categorical are not supported at this time
Error message
> 1 ndim Categorical are not supported at this time
What it means
Raised in `Categorical.__init__` when the input values is a numpy ndarray with `ndim > 1`. Categoricals are strictly 1-D; multi-dimensional data has no defined category layout, so pandas preemptively rejects it before `sanitize_array` would raise a less informative error.
Solutions
- Flatten or select a single column: `pd.Categorical(arr[:, 0])` or `pd.Categorical(arr.ravel())` if a 1-D view is meaningful.
- Apply `astype('category')` per-column: `df.apply(lambda s: s.astype('category'))`.
- Reshape the input to 1-D with `.reshape(-1)` only if the data is genuinely 1-D stored in a higher-rank container.
- Verify `arr.ndim == 1` before construction as a guard.
Example fix
# before import numpy as np import pandas as pd arr = np.array([['a', 'b'], ['c', 'd']]) cat = pd.Categorical(arr) # NotImplementedError # after (per column) cats = [pd.Categorical(arr[:, j]) for j in range(arr.shape[1])]
Defensive patterns
Strategy: validation
Validate before calling
import numpy as np
def ensure_1d(values):
if isinstance(values, np.ndarray) and values.ndim > 1:
raise ValueError(f"expected 1-D input, got shape {values.shape}")
return values Type guard
def is_one_dimensional(values) -> bool:
return not (hasattr(values, 'ndim') and values.ndim > 1) Try / catch
try:
cat = pd.Categorical(arr)
except NotImplementedError as e:
if 'ndim' in str(e) and getattr(arr, 'ndim', 0) > 1:
cat = pd.Categorical(arr.ravel())
else:
raise Prevention
- Check `arr.ndim == 1` before constructing a Categorical from an ndarray.
- Apply `.astype('category')` to Series/DataFrame columns, never to a 2-D DataFrame directly.
- In tensor/array interop, squeeze or select a column before passing to pandas.
When it happens
Trigger: Passing a 2-D numpy array or a DataFrame's `.values` of shape `(n, m)` directly to `pd.Categorical(...)` or `.astype('category')` on a DataFrame.
Common situations: Calling `.astype('category')` on a whole DataFrame instead of per-column; reshaping pipelines that accidentally keep an extra dimension; Tensor/array interop code that hands off 2-D arrays.
Related errors
- Categorical input must be list-like
- 'values' is not ordered, please explicitly specify the…
- Accumulation not supported for
- Array with ndim > 2 is not supported.
- axis is out of bounds for array of dimension
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/bd6b04f0352bc0fb.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/categorical.py:435
# sanitize input
vdtype = getattr(values, "dtype", None)
if isinstance(vdtype, CategoricalDtype):
if dtype.categories is None:
dtype = CategoricalDtype(values.categories, dtype.ordered)
elif isinstance(values, range):
from pandas.core.indexes.range import RangeIndex
values = RangeIndex(values)
elif not isinstance(values, (ABCIndex, ABCSeries, ExtensionArray)):
values = com.convert_to_list_like(values)
if isinstance(values, list) and len(values) == 0:
# By convention, empty lists result in object dtype:
values = np.array([], dtype=object)
elif isinstance(values, np.ndarray):
if values.ndim > 1:
# preempt sanitize_array from raising ValueError
raise NotImplementedError(
"> 1 ndim Categorical are not supported at this time"
)
values = sanitize_array(values, None)
else:
# i.e. must be a list
arr = sanitize_array(values, None)
null_mask = isna(arr)
if null_mask.any():
# We remove null values here, then below will re-insert
# them, grep "full_codes"
arr_list = [values[idx] for idx in np.where(~null_mask)[0]]
# GH#44900 Do not cast to float if we have only missing values
if arr_list or arr.dtype == "object":
sanitize_dtype = None
else:
sanitize_dtype = arr.dtype
View on GitHub (pinned to 3b7651241d)