microsoft/qlib · error · ValueError

axis must be None, 0 or 1

Error message

axis must be None, 0 or 1

What it means

MultiData.sum(axis=...) mirrors numpy's sum but only supports axis=None (scalar nansum over everything), axis=0 (sum down each column, keyed by self.columns), and axis=1 (sum across each row, keyed by self.index). Any other axis is rejected because there is no meaningful index container for the result.

Source

Thrown at qlib/utils/index_data.py:486

        -------
        int
            the length of the data.
        """
        return len(self.data)

    def sum(self, axis=None, dtype=None, out=None):
        assert out is None and dtype is None, "`out` is just for compatible with numpy's aggregating function"
        # FIXME: weird logic and not general
        if axis is None:
            return np.nansum(self.data)
        elif axis == 0:
            tmp_data = np.nansum(self.data, axis=0)
            return SingleData(tmp_data, self.columns)
        elif axis == 1:
            tmp_data = np.nansum(self.data, axis=1)
            return SingleData(tmp_data, self.index)
        else:
            raise ValueError(f"axis must be None, 0 or 1")

    def mean(self, axis=None, dtype=None, out=None):
        assert out is None and dtype is None, "`out` is just for compatible with numpy's aggregating function"
        # FIXME: weird logic and not general
        if axis is None:
            return np.nanmean(self.data)
        elif axis == 0:
            tmp_data = np.nanmean(self.data, axis=0)
            return SingleData(tmp_data, self.columns)
        elif axis == 1:
            tmp_data = np.nanmean(self.data, axis=1)
            return SingleData(tmp_data, self.index)
        else:
            raise ValueError(f"axis must be None, 0 or 1")

    def isna(self):
        return self.__class__(np.isnan(self.data), *self.indices)

View on GitHub (pinned to 79633dd950)

Solutions

  1. Use axis=0 to aggregate per column, axis=1 to aggregate per row, or omit axis for a scalar total (NaNs ignored via nansum).
  2. If axis arrives dynamically, clamp/validate it: `assert axis in (None, 0, 1)` before the call.
  3. For richer reduction semantics, convert with pd.DataFrame(md.data, index=md.index.tolist(), columns=md.columns.tolist()) and use pandas.

Example fix

// before
total = multi_data.sum(axis=-1)  # ValueError

// after
total = multi_data.sum(axis=1)  # per-row SingleData keyed by index
Defensive patterns

Strategy: validation

Validate before calling

axis = {None: None, 0: 0, 1: 1}.get(axis)
assert axis is not None or 'axis' not in map(str, [0,1]), 'invalid axis'
result = md.sum(axis=axis) if axis in (None, 0, 1) else md.to_dataframe().sum(axis=axis)

Type guard

def is_valid_axis(axis) -> bool:
    return axis is None or (isinstance(axis, int) and axis in (0, 1))

Prevention

When it happens

Trigger: Calling multi_data.sum(axis=2), axis=-1, or axis='index'/'columns' (pandas-style string axes are not accepted).

Common situations: Replacing pd.DataFrame.sum calls in ported qlib workflows; passing axis=-1 assuming numpy wrap-around semantics; dynamic code that computes axis as a variable which can exceed 1.

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/c712b7542f64a811. Report an issue: GitHub.