{"record":{"id":"7d9e039bd4118c5f","repo":"microsoft/qlib","slug":"catboost-doesn-t-support-multi-label-training","errorCode":null,"errorMessage":"CatBoost doesn't support multi-label training","messagePattern":"CatBoost doesn't support multi-label training","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/catboost_model.py","lineNumber":52,"sourceCode":"        evals_result=dict(),\n        reweighter=None,\n        **kwargs,\n    ):\n        df_train, df_valid = dataset.prepare(\n            [\"train\", \"valid\"],\n            col_set=[\"feature\", \"label\"],\n            data_key=DataHandlerLP.DK_L,\n        )\n        if df_train.empty or df_valid.empty:\n            raise ValueError(\"Empty data from dataset, please check your dataset config.\")\n        x_train, y_train = df_train[\"feature\"], df_train[\"label\"]\n        x_valid, y_valid = df_valid[\"feature\"], df_valid[\"label\"]\n\n        # CatBoost needs 1D array as its label\n        if y_train.values.ndim == 2 and y_train.values.shape[1] == 1:\n            y_train_1d, y_valid_1d = np.squeeze(y_train.values), np.squeeze(y_valid.values)\n        else:\n            raise ValueError(\"CatBoost doesn't support multi-label training\")\n\n        if reweighter is None:\n            w_train = None\n            w_valid = None\n        elif isinstance(reweighter, Reweighter):\n            w_train = reweighter.reweight(df_train).values\n            w_valid = reweighter.reweight(df_valid).values\n        else:\n            raise ValueError(\"Unsupported reweighter type.\")\n\n        train_pool = Pool(data=x_train, label=y_train_1d, weight=w_train)\n        valid_pool = Pool(data=x_valid, label=y_valid_1d, weight=w_valid)\n\n        # Initialize the catboost model\n        self._params[\"iterations\"] = num_boost_round\n        self._params[\"early_stopping_rounds\"] = early_stopping_rounds\n        self._params[\"verbose_eval\"] = verbose_eval\n        self._params[\"task_type\"] = \"GPU\" if get_gpu_device_count() > 0 else \"CPU\"","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/catboost_model.py#L34-L70","documentation":"Thrown by CatBoostModel.fit when the label block is not a single-column 2D array. CatBoost's Pool accepts only a 1D label (scalar per sample), so qlib squeezes the label only when it is exactly (N, 1); anything else (multi-column labels, or a raw 1D series that already lost its column axis) is rejected.","triggerScenarios":"Configuring the DatasetH label as multiple expressions (e.g. \"Ref($close, -2)/Ref($close, -1) - 1; $volume/$amount\"), producing y_train.values.shape[1] > 1; or a label pipeline that returns a DataFrame with != 1 columns.","commonSituations":"Copying a workflow config with a multi-task label; adding extra label columns for custom metrics and forgetting the model constraint; switching from a model that tolerates multi-label (e.g. some neural models) to CatBoostModel.","solutions":["Reduce the label to exactly one expression in the handler config, e.g. label: [\"Ref($close, -2)/Ref($close, -1) - 1\"]","If multi-output prediction is required, use a model that supports it (e.g. a PyTorch model with a matching output head)"],"exampleFix":"# before (qlib config yaml)\nlabel: [\"Ref($close, -2)/Ref($close, -1) - 1\", \"$volume\"]\n\n# after\nlabel: [\"Ref($close, -2)/Ref($close, -1) - 1\"]","handlingStrategy":"validation","validationCode":"y = dataset.prepare(\"train\", col_set=\"label\", data_key=\"learn\")\nassert y.values.ndim == 2 and y.values.shape[1] == 1, f\"CatBoost needs a single label column, got {y.shape[1]}\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the handler label list to exactly one expression for all GBM-family models","Add a startup assertion on label column count when sharing configs across models"],"tags":["catboost","multi-label","label-config","qlib"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}