pandas-dev/pandas · error · ValueError

Is not a partition because union is not the whole.

Error message

Is not a partition because union is not the whole.

What it means

Thrown by _check_is_partition in pandas/core/arrays/sparse/scipy_sparse.py:37, the companion check to the intersection error. Here the union of row_levels and column_levels does not cover every level of the MultiIndex — at least one level is omitted from both groups. COO conversion needs to place every index level on exactly one axis, so an uncovered level is rejected.

Solutions

  1. List every level across the two groups: row_levels=[0], column_levels=[1,2] for a 3-level index.
  2. Compute levels programmatically: row_levels=[0]; column_levels=[l for l in range(ss.index.nlevels) if l not in row_levels].
  3. Verify coverage: assert set(row_levels) | set(column_levels) == set(range(ss.index.nlevels)).

Example fix

// before
# 3-level MultiIndex
ss.sparse.to_coo(row_levels=[0], column_levels=[1])  # level 2 uncovered

// after
ss.sparse.to_coo(row_levels=[0], column_levels=[1, 2])
Defensive patterns

Strategy: validation

Validate before calling

def covering_levels(row_levels, column_levels, nlevels):
    missing = set(range(nlevels)) - (set(row_levels) | set(column_levels))
    if missing:
        raise ValueError(f'levels {missing} not assigned to any axis')
    return row_levels, column_levels

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Calling ss.sparse.to_coo(row_levels=[0], column_levels=[1]) on a Series whose MultiIndex has 3 levels — level 2 is in neither group. Forgetting to list a level after extending the MultiIndex.

Common situations: Default row_levels=[0], column_levels=[1] used on a 3-level index without updating the call. Refactoring code that added a level to the MultiIndex but did not update to_coo arguments.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/cedcb108aa18d9a4. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/arrays/sparse/scipy_sparse.py:37

if TYPE_CHECKING:
    from collections.abc import Iterable

    import numpy as np
    import scipy.sparse

    from pandas._typing import (
        IndexLabel,
        npt,
    )


def _check_is_partition(parts: Iterable, whole: Iterable) -> None:
    whole = set(whole)
    parts = [set(x) for x in parts]
    if set.intersection(*parts) != set():
        raise ValueError("Is not a partition because intersection is not null.")
    if set.union(*parts) != whole:
        raise ValueError("Is not a partition because union is not the whole.")


def _levels_to_axis(
    ss,
    levels: tuple[int] | list[int],
    valid_ilocs: npt.NDArray[np.intp],
    sort_labels: bool = False,
) -> tuple[npt.NDArray[np.intp], list[IndexLabel]]:
    """
    For a MultiIndexed sparse Series `ss`, return `ax_coords` and `ax_labels`,
    where `ax_coords` are the coordinates along one of the two axes of the
    destination sparse matrix, and `ax_labels` are the labels from `ss`' Index
    which correspond to these coordinates.

    Parameters
    ----------
    ss : Series
    levels : tuple/list

View on GitHub (pinned to 3b7651241d)