microsoft/qlib · error · ValueError

LightGBM doesn't support multi-label training

Error message

LightGBM doesn't support multi-label training

What it means

Thrown by DEnsembleModel._prepare_data_gbm when the label block is not exactly one column. The underlying base model is LightGBM, whose Dataset label must be 1D, so qlib only squeezes labels of shape (N, 1) and rejects multi-column labels.

Source

Thrown at qlib/contrib/model/double_ensemble.py:134

            dtrain,
            num_boost_round=self.epochs,
            valid_sets=[dtrain, dvalid],
            valid_names=["train", "valid"],
            callbacks=callbacks,
        )
        evals_result["train"] = list(evals_result["train"].values())[0]
        evals_result["valid"] = list(evals_result["valid"].values())[0]
        return model

    def _prepare_data_gbm(self, df_train, df_valid, weights, features):
        x_train, y_train = df_train["feature"].loc[:, features], df_train["label"]
        x_valid, y_valid = df_valid["feature"].loc[:, features], df_valid["label"]

        # Lightgbm need 1D array as its label
        if y_train.values.ndim == 2 and y_train.values.shape[1] == 1:
            y_train, y_valid = np.squeeze(y_train.values), np.squeeze(y_valid.values)
        else:
            raise ValueError("LightGBM doesn't support multi-label training")

        dtrain = lgb.Dataset(x_train, label=y_train, weight=weights)
        dvalid = lgb.Dataset(x_valid, label=y_valid)
        return dtrain, dvalid

    def sample_reweight(self, loss_curve, loss_values, k_th):
        """
        the SR module of Double Ensemble
        :param loss_curve: the shape is NxT
        the loss curve for the previous sub-model, where the element (i, t) if the error on the i-th sample
        after the t-th iteration in the training of the previous sub-model.
        :param loss_values: the shape is N
        the loss of the current ensemble on the i-th sample.
        :param k_th: the index of the current sub-model, starting from 1
        :return: weights
        the weights for all the samples.
        """
        # normalize loss_curve and loss_values with ranking

View on GitHub (pinned to 79633dd950)

Solutions

  1. Set the handler label to a single expression, e.g. label: ["Ref($close, -2)/Ref($close, -1) - 1"]
  2. Use a multi-output-capable model if you truly need several targets

Example fix

# before (handler config)
label: ["Ref($close, -2)/Ref($close, -1) - 1", "Ref($high, -1)/$close - 1"]

# after
label: ["Ref($close, -2)/Ref($close, -1) - 1"]
Defensive patterns

Strategy: validation

Validate before calling

y = dataset.prepare("train", col_set="label", data_key="learn")
assert y.values.shape[1] == 1, "Double Ensemble (LightGBM base) supports only single-column labels"

Prevention

When it happens

Trigger: Running Double Ensemble (workflow 'DENsemble' / model.cls: DEnsembleModel) with a handler whose label list has more than one expression.

Common situations: Reusing a multi-label handler config from another model; adding auxiliary label columns for analysis.

Related errors


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