microsoft/qlib · error · ValueError

model is not fitted yet!

Error message

model is not fitted yet!

What it means

Thrown by DEnsembleModel.predict when self.ensemble is None, intended to guard prediction before fit. Note a caveat: __init__ sets self.ensemble = [], so the attribute is normally an empty list rather than None — with a stock instance, predict before fit returns a zero vector divided by sum(sub_weights) instead of raising. The error effectively fires only if ensemble is explicitly set to None.

Source

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

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

            N = x_train.shape[0]
            loss_curve = pd.DataFrame(np.zeros((N, num_trees)))
            pred_tree = np.zeros(N, dtype=float)
            for i_tree in range(num_trees):
                pred_tree += model.predict(x_train.values, start_iteration=i_tree, num_iteration=1)
                loss_curve.iloc[:, i_tree] = self.get_loss(y_train, pred_tree)
        else:
            raise ValueError("not implemented yet")
        return loss_curve

    def predict(self, dataset: DatasetH, segment: Union[Text, slice] = "test"):
        if self.ensemble is None:
            raise ValueError("model is not fitted yet!")
        x_test = dataset.prepare(segment, col_set="feature", data_key=DataHandlerLP.DK_I)
        pred = pd.Series(np.zeros(x_test.shape[0]), index=x_test.index)
        for i_sub, submodel in enumerate(self.ensemble):
            feat_sub = self.sub_features[i_sub]
            pred += (
                pd.Series(submodel.predict(x_test.loc[:, feat_sub].values), index=x_test.index)
                * self.sub_weights[i_sub]
            )
        pred = pred / np.sum(self.sub_weights)
        return pred

    def predict_sub(self, submodel, df_data, features):
        x_data = df_data["feature"].loc[:, features]
        pred_sub = pd.Series(submodel.predict(x_data.values), index=x_data.index)
        return pred_sub

    def get_feature_importance(self, *args, **kwargs) -> pd.Series:
        """get feature importance

View on GitHub (pinned to 79633dd950)

Solutions

  1. Always call fit(dataset) and let it complete before predict(dataset)
  2. Wrap fit in try/except and do not proceed to predict on failure
  3. Defensively check isinstance(model.ensemble, list) and len(model.ensemble) == model.num_models before predicting, since the built-in None check is unreliable

Example fix

# before
model = DEnsembleModel(num_models=5)
pred = model.predict(dataset)  # silent zeros, not the expected guard

# after
model.fit(dataset)
assert len(model.ensemble) == model.num_models
pred = model.predict(dataset)
Defensive patterns

Strategy: validation

Validate before calling

# built-in None-check is unreliable (ensemble is [] not None); validate explicitly
assert isinstance(model.ensemble, list) and len(model.ensemble) == model.num_models, "fit() must complete before predict()"

Prevention

When it happens

Trigger: Calling predict on a model whose fit failed before the ensemble loop or that was manually mutated (ensemble set to None); in practice the guard is largely dead code because fit/__init__ initialize an empty list.

Common situations: Exceptions during fit partially constructing the object; users assuming the guard protects them from untrained prediction when it actually does not reliably do so.

Related errors


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