pandas-dev/pandas · error · NotImplementedError

can only perform ops with 1-d structures

Error message

can only perform ops with 1-d structures

What it means

Raised by BaseMaskedArray._arith_method when the right-hand operand (other) is a list-like whose numpy conversion has ndim > 1. Masked array arithmetic is only defined for scalars or 1-D structures aligned elementwise with self; broadcasting against matrices/DataFrames is unsupported at this layer.

Source

Thrown at pandas/core/arrays/masked.py:984

            )

        if (
            not hasattr(other, "dtype")
            and is_list_like(other)
            and len(other) == len(self)
        ):
            # Try inferring masked dtype instead of casting to object
            other = pd_array(other)
            other = extract_array(other, extract_numpy=True)

        if isinstance(other, BaseMaskedArray):
            other, omask = other._data, other._mask

        elif is_list_like(other):
            if not isinstance(other, ExtensionArray):
                other = np.asarray(other)
            if other.ndim > 1:
                raise NotImplementedError("can only perform ops with 1-d structures")

        # We wrap the non-masked arithmetic logic used for numpy dtypes
        #  in Series/Index arithmetic ops.
        other = ops.maybe_prepare_scalar_for_op(other, (len(self),))
        pd_op = ops.get_array_op(op)
        other = ensure_wrapped_if_datetimelike(other)

        if isinstance(other, ExtensionArray) and isinstance(other.dtype, ArrowDtype):
            # GH#58602
            return NotImplemented

        if op_name in {"pow", "rpow"} and isinstance(other, np.bool_):
            # Avoid DeprecationWarning: In future, it will be an error
            #  for 'np.bool_' scalars to be interpreted as an index
            #  e.g. test_array_scalar_like_equivalence
            other = bool(other)

        mask = self._propagate_mask(omask, other)

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Flatten the operand to 1-D: arr + matrix.ravel() or arr + matrix[:, 0].
  2. Operate through a Series/DataFrame so pandas handles alignment and broadcasting.
  3. Squeeze a (n,1) array: arr + col_vector.squeeze(axis=1).

Example fix

// before
arr + np.array([[1, 2], [3, 4]])  # raises

// after
arr + np.array([[1, 2], [3, 4]]).ravel()
Defensive patterns

Strategy: type-guard

Validate before calling

import numpy as np

def ensure_1d(other):
    arr = np.asarray(other)
    if arr.ndim > 1:
        arr = arr.reshape(-1)[:len(arr)] if arr.size else arr
        arr = arr.ravel()
    return arr

Type guard

def is_scalar_or_1d(other) -> bool:
    import numpy as np
    return np.isscalar(other) or (hasattr(other, 'ndim') and other.ndim == 1) or not hasattr(other, '__array__')

Try / catch

try:
    res = arr + other
except NotImplementedError as e:
    if "1-d structures" in str(e):
        res = arr + np.asarray(other).ravel()
    else:
        raise

Prevention

When it happens

Trigger: Doing arr + matrix, arr * df.values (2-D), or arr op np.array([[..],[..]]) where the right operand converts to an ndarray with ndim>=2.

Common situations: Passing a 2-D numpy array or DataFrame where a Series/scalar was expected; refactoring elementwise ops to broadcast against a matrix; misusing a column vector (n,1) in place of a 1-D array.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/18c27b85705bf09a. Report an issue: GitHub.