{"record":{"id":"1f0368bed047b793","repo":"microsoft/qlib","slug":"not-implemented-yet","errorCode":null,"errorMessage":"not implemented yet","messagePattern":"not implemented yet","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/double_ensemble.py","lineNumber":225,"sourceCode":"        g[\"g_value\"].replace(np.nan, 0, inplace=True)\n\n        # divide features into bins_fs bins\n        g[\"bins\"] = pd.cut(g[\"g_value\"], self.bins_fs)\n\n        # randomly sample features from bins to construct the new features\n        res_feat = []\n        sorted_bins = sorted(g[\"bins\"].unique(), reverse=True)\n        for i_b, b in enumerate(sorted_bins):\n            b_feat = features[g[\"bins\"] == b]\n            num_feat = int(np.ceil(self.sample_ratios[i_b] * len(b_feat)))\n            res_feat = res_feat + np.random.choice(b_feat, size=num_feat, replace=False).tolist()\n        return pd.Index(set(res_feat))\n\n    def get_loss(self, label, pred):\n        if self.loss == \"mse\":\n            return (label - pred) ** 2\n        else:\n            raise ValueError(\"not implemented yet\")\n\n    def retrieve_loss_curve(self, model, df_train, features):\n        if self.base_model == \"gbm\":\n            num_trees = model.num_trees()\n            x_train, y_train = df_train[\"feature\"].loc[:, features], df_train[\"label\"]\n            # Lightgbm need 1D array as its label\n            if y_train.values.ndim == 2 and y_train.values.shape[1] == 1:\n                y_train = np.squeeze(y_train.values)\n            else:\n                raise ValueError(\"LightGBM doesn't support multi-label training\")\n\n            N = x_train.shape[0]\n            loss_curve = pd.DataFrame(np.zeros((N, num_trees)))\n            pred_tree = np.zeros(N, dtype=float)\n            for i_tree in range(num_trees):\n                pred_tree += model.predict(x_train.values, start_iteration=i_tree, num_iteration=1)\n                loss_curve.iloc[:, i_tree] = self.get_loss(y_train, pred_tree)\n        else:","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/double_ensemble.py#L207-L243","documentation":"Thrown by DEnsembleModel.get_loss when self.loss is not \"mse\". Double Ensemble's sample-reweighting and feature-selection modules need per-sample training loss; only mean squared error is implemented, so any other loss string (e.g. \"mae\", a LightGBM objective name) is rejected during fit.","triggerScenarios":"Constructing DEnsembleModel(loss=\"mae\") or loss=\"binary\" etc.; loss is forwarded into params as the objective, but the reweighting math only knows \"mse\".","commonSituations":"Treating loss as a free LightGBM objective parameter; porting a classification objective into Double Ensemble.","solutions":["Use loss=\"mse\" (the supported value)","For classification-style tasks, encode the target appropriately and keep mse, or pick a different model class"],"exampleFix":"# before\nmodel = DEnsembleModel(loss=\"mae\")\n\n# after\nmodel = DEnsembleModel(loss=\"mse\")","handlingStrategy":"validation","validationCode":"assert loss == \"mse\", \"DEnsembleModel supports only loss='mse' (needed for sample reweighting and feature selection)\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not treat DEnsembleModel's loss as a free LightGBM objective string","Keep loss='mse' when using Double Ensemble workflows"],"tags":["double-ensemble","loss-function","not-implemented","qlib"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}