hscredit.core.models.boosting.xgboost_model 源代码

"""XGBoost风控模型.

基于XGBoost实现的风控模型,支持自定义损失函数和评估指标。

**依赖**
pip install xgboost

**参考样例**

>>> from hscredit.core.models import XGBoost
>>> model = XGBoost(
...     max_depth=5,          # 树最大深度
...     learning_rate=0.1,    # 学习率
...     n_estimators=100,     # 树数量
...     eval_metric=['auc', 'ks']  # 评估指标
... )
>>> model.fit(X_train, y_train)           # 训练模型
>>> proba = model.predict_proba(X_test)    # 预测概率
>>> report = model.generate_report(X_train, y_train, X_test, y_test)  # 生成评估报告
"""

import copy
import inspect
import logging
from typing import Any, Dict, List, Optional, Tuple, Union
from .._lifecycle import record_training

import numpy as np
import pandas as pd

logger = logging.getLogger(__name__)

try:
    import xgboost as xgb

    XGBOOST_AVAILABLE = True
except ImportError:
    XGBOOST_AVAILABLE = False
    xgb = None

from ..base import BaseRiskModel, resolve_custom_objective
from ..losses.base import BaseLoss, BaseMetric


class _KSEvaluationCallback(xgb.callback.TrainingCallback if XGBOOST_AVAILABLE else object):
    """保留 KS 曲线;矩阵句柄只在训练时创建,不进入保存制品。"""

    def __init__(self, eval_set, early_stopping=None):
        self.eval_set = eval_set
        self.early_stopping = early_stopping

    def before_training(self, model):
        self.matrices = [xgb.DMatrix(X, label=y, enable_categorical=True) for X, y in self.eval_set]
        return self.early_stopping.before_training(model) if self.early_stopping else model

    def after_iteration(self, model, epoch, evals_log):
        from sklearn.metrics import roc_curve

        for index, matrix in enumerate(self.matrices):
            prediction = model.predict(matrix, iteration_range=(0, epoch + 1))
            fpr, tpr, _ = roc_curve(matrix.get_label(), prediction, pos_label=1)
            evals_log.setdefault(f"validation_{index}", {}).setdefault("ks", []).append(
                float(np.max(np.abs(tpr - fpr)))
            )
        return self.early_stopping.after_iteration(model, epoch, evals_log) if self.early_stopping else False

    def after_training(self, model):
        self.__dict__.pop("matrices", None)
        return self.early_stopping.after_training(model) if self.early_stopping else model

    def __getstate__(self):
        return {name: value for name, value in self.__dict__.items() if name != "matrices"}


[文档] class XGBoost(BaseRiskModel): """XGBoost风控模型 - 基于内部建模经验优化. 基于XGBoost的二分类模型,针对风控场景优化。 参考内部建模经验,支持自动scale_pos_weight计算、KS评估指标等。 **参数** :param max_depth: 树最大深度,默认6 - 内部经验: 特征>1000时建议5-13,否则3-9 :param learning_rate: 学习率,默认0.1 - 内部经验: 一般0.01-0.3,常用0.1 :param n_estimators: 树的数量,默认100 - 内部经验: 样本>10000时50-300,否则20-100 :param min_child_weight: 叶子节点最小样本权重和,默认1 - 内部经验: 样本>10000时10-2000,否则10-300 :param subsample: 样本采样比例,默认0.8 - 内部经验: 常用0.6-0.9防止过拟合 :param colsample_bytree: 特征采样比例,默认0.8 - 内部经验: 常用0.6-0.9防止过拟合 :param colsample_bylevel: 每层的特征采样比例,默认1.0 :param reg_alpha: L1正则化系数,默认0 - 内部经验: 常用0, 0.01, 0.1, 1, 10, 100 :param reg_lambda: L2正则化系数,默认1 :param scale_pos_weight: 正负样本权重比,默认'auto' - 'auto': 自动计算 (当bad_rate<0.05时) - float: 自定义权重 - 内部经验: 当bad_rate<0.05时设置0.05 * n_samples / n_positive :param gamma: 节点分裂所需的最小损失减少,默认0 :param max_delta_step: 每棵树权重改变的最大步长,默认0 :param tree_method: 树构建算法,默认'hist' - 'hist': 直方图算法(推荐,速度快) - 'exact': 精确贪心算法 - 'approx': 近似算法 - 'gpu_hist': GPU直方图算法 :param objective: 目标函数,默认'binary:logistic' :param eval_metric: 评估指标,可选名称、名称列表或 BaseMetric 对象;自定义损失默认使用其配套指标 - 支持'ks'作为自定义评估指标(风控常用) - 多个指标时,默认使用第一个指标进行早停 :param early_stopping_rounds: 早停轮数,默认None - 连续N轮没有改善则停止训练 - XGBoost 2.0+ 需要在构造函数中传入此参数 :param early_stopping_metric: 用于早停的评估指标名称,默认None(使用第一个指标) - 当eval_metric有多个时,指定用哪个指标进行早停判断 - XGBoost 2.0+ 使用方式: 传入metric名称,如 'auc', 'logloss', 'error' - 注意: 指标名称必须是eval_metric中指定的名称之一 - 例如: eval_metric=['auc','logloss']时,可指定'auc'或'logloss'作为早停指标 :param early_stopping_data: 用于早停的验证集名称,默认None(使用第一个验证集) - XGBoost内部会自动命名为'validation_0', 'validation_1'等 - 通常不需要指定,除非有多个验证集 :param validation_fraction: 验证集比例,默认0.2 :param random_state: 随机种子,默认None :param n_jobs: 并行任务数,默认-1 :param verbose: 是否输出详细信息,默认False :param params: XGBoost原生参数字典,默认None - 如果传入,将覆盖其他参数设置 - 可直接使用XGBoost原生参数名 :param kwargs: 其他XGBoost参数 **属性** :ivar feature_importances_: 特征重要性 :ivar evals_result_: 训练过程评估结果 :ivar best_iteration_: 最佳迭代次数 :ivar best_score_: 最佳得分 :ivar scale_pos_weight_: 实际使用的scale_pos_weight值 :ivar booster_: 底层XGBoost模型 **参考样例** >>> # 基础使用 >>> model = XGBoost(max_depth=5, learning_rate=0.1) >>> model.fit(X_train, y_train) >>> # 自动处理不平衡数据 >>> model = XGBoost(scale_pos_weight='auto') >>> model.fit(X_train, y_train) >>> # 使用KS作为评估指标 >>> model = XGBoost(eval_metric='ks') >>> model.fit(X_train, y_train) >>> # 使用原生XGBoost参数 >>> params = {'max_depth': 5, 'learning_rate': 0.05, 'subsample': 0.8} >>> model = XGBoost(params=params) >>> model.fit(X_train, y_train) >>> # 早停设置 - 使用多个评估指标,指定logloss作为早停指标(越小越好) >>> model = XGBoost( ... n_estimators=1000, ... eval_metric=['auc', 'logloss'], ... early_stopping_rounds=10, ... early_stopping_metric='logloss' ... ) >>> model.fit(X_train, y_train) >>> print(f'最佳迭代次数: {model.best_iteration_}') >>> # 早停设置 - 使用AUC作为早停指标(越大越好) >>> model = XGBoost( ... n_estimators=1000, ... eval_metric=['auc', 'logloss'], ... early_stopping_rounds=10, ... early_stopping_metric='auc' ... ) >>> model.fit(X_train, y_train) **引用** 基于 XGBoost 梯度提升框架,见 Chen, T. & Guestrin, C. (2016). *XGBoost: A Scalable Tree Boosting System.* KDD; 文档 https://xgboost.readthedocs.io/ 。 """ _preserve_dataframe = True _parameter_aliases = { "learning_rate": ("eta",), "reg_alpha": ("alpha",), "reg_lambda": ("lambda",), "n_jobs": ("nthread",), "random_state": ("seed",), } def __init__( self, max_depth: int = 6, learning_rate: float = 0.1, n_estimators: int = 100, min_child_weight: float = 1, subsample: float = 0.8, colsample_bytree: float = 0.8, colsample_bylevel: float = 1.0, reg_alpha: float = 0, reg_lambda: float = 1, scale_pos_weight: Union[str, float] = "auto", gamma: float = 0, max_delta_step: float = 0, tree_method: str = "hist", objective: str = "binary:logistic", eval_metric: Union[str, List[str], BaseMetric, None] = None, early_stopping_rounds: Optional[int] = None, early_stopping_metric: Optional[str] = None, early_stopping_data: Optional[str] = None, validation_fraction: float = 0.2, random_state: Optional[int] = None, n_jobs: int = -1, verbose: bool = False, params: Optional[Dict[str, Any]] = None, scorecard_params: Optional[Dict[str, Any]] = None, **kwargs, ): if not XGBOOST_AVAILABLE: raise ImportError("XGBoost未安装,请使用 pip install xgboost 安装") # sklearn clone 必须能够原样往返构造输入,原生覆盖值只用于实际训练。 self._constructor_params = { name: value for name, value in locals().items() if name not in {"self", "kwargs", "__class__"} } self._constructor_kwargs = dict(kwargs) # 保存原生params参数 self.params = params # 用于sklearn get_params兼容性 self._native_params = dict(params or {}) # 从params中提取参数(如果提供了原生参数) max_depth = self._native_params.get("max_depth", max_depth) learning_rate = self._native_params.get("learning_rate", learning_rate) n_estimators = self._native_params.get("n_estimators", n_estimators) min_child_weight = self._native_params.get("min_child_weight", min_child_weight) subsample = self._native_params.get("subsample", subsample) colsample_bytree = self._native_params.get("colsample_bytree", colsample_bytree) colsample_bylevel = self._native_params.get("colsample_bylevel", colsample_bylevel) reg_alpha = self._native_params.get("reg_alpha", reg_alpha) reg_lambda = self._native_params.get("reg_lambda", reg_lambda) scale_pos_weight = self._native_params.get("scale_pos_weight", scale_pos_weight) gamma = self._native_params.get("gamma", gamma) max_delta_step = self._native_params.get("max_delta_step", max_delta_step) tree_method = self._native_params.get("tree_method", tree_method) objective = self._native_params.get("objective", objective) random_state = self._native_params.get("random_state", random_state) n_jobs = self._native_params.get("n_jobs", n_jobs) # 从params中提取early_stopping_rounds(优先级最高) early_stopping_rounds = self._native_params.get("early_stopping_rounds", early_stopping_rounds) super().__init__( objective=objective, eval_metric=eval_metric, early_stopping_rounds=early_stopping_rounds, validation_fraction=validation_fraction, random_state=random_state, n_jobs=n_jobs, verbose=verbose, scorecard_params=scorecard_params, **kwargs, ) # 早停相关参数 self.early_stopping_metric = early_stopping_metric self.early_stopping_data = early_stopping_data # XGBoost特有参数 self.max_depth = max_depth self.learning_rate = learning_rate self.n_estimators = n_estimators self.min_child_weight = min_child_weight self.subsample = subsample self.colsample_bytree = colsample_bytree self.colsample_bylevel = colsample_bylevel self.reg_alpha = reg_alpha self.reg_lambda = reg_lambda self._scale_pos_weight_input = scale_pos_weight # 保存原始输入 self.scale_pos_weight = scale_pos_weight self.gamma = gamma self.max_delta_step = max_delta_step self.tree_method = tree_method self.scale_pos_weight_ = None # 实际使用的值
[文档] @record_training def fit( self, X: Union[np.ndarray, pd.DataFrame], y: Optional[Union[np.ndarray, pd.Series]] = None, sample_weight: Optional[np.ndarray] = None, eval_set: Optional[List[Tuple]] = None, **fit_params, ) -> "XGBoost": """训练XGBoost模型. 支持两种调用方式: 1. 常规方式: fit(X, y) 2. scorecardpipeline风格: fit(X) 在init中指定target :param X: 特征矩阵 :param y: 目标变量,可选 :param sample_weight: 样本权重 :param eval_set: 验证集列表 :param fit_params: 其他fit参数 :return: self """ eval_metric = fit_params.pop("eval_metric", self._native_params.get("eval_metric", self.eval_metric)) objective = self._native_params.get("objective", self.kwargs.get("objective", self.objective)) if eval_metric is None and isinstance(objective, BaseLoss): eval_metric = objective.metric() metric_object = eval_metric if isinstance(eval_metric, BaseMetric) else None early_stopping_rounds = fit_params.pop( "early_stopping_rounds", self._native_params.get("early_stopping_rounds", self.early_stopping_rounds) ) # 准备数据(支持从X中提取target) X, y, sample_weight = self._prepare_data(X, y, sample_weight, extract_target=True, training=True) scorecard_sample_weight = sample_weight self._validate_probability_scorecard_labels(y) eval_set = self._prepare_eval_set(eval_set) # 保存特征信息 self.n_features_in_ = X.shape[1] self.classes_ = np.unique(y) # 自动计算scale_pos_weight(内部建模经验:当bad_rate<0.05时) if self.scale_pos_weight == "auto": pos_ratio = np.mean(y == 1) if pos_ratio < 0.05: # 内部经验: 0.05 * n_samples / n_positive self.scale_pos_weight_ = 0.05 * len(y) / np.sum(y == 1) if self.verbose: logger.info(f"自动计算scale_pos_weight: {self.scale_pos_weight_:.2f} (bad_rate={pos_ratio:.4f})") else: self.scale_pos_weight_ = 1.0 else: self.scale_pos_weight_ = self.scale_pos_weight # 创建验证集 auto_eval_split = eval_set is None and self.validation_fraction > 0 and early_stopping_rounds is not None sw_val = None if auto_eval_split: X_train, X_val, y_train, y_val, sw_train, sw_val = self._create_eval_set(X, y, sample_weight) eval_set = [(X_val, y_val)] sample_weight = sw_train else: X_train, y_train = X, y # 构建参数 - 在构造函数中传入所有参数 params = { "max_depth": self.max_depth, "learning_rate": self.learning_rate, "n_estimators": self.n_estimators, "min_child_weight": self.min_child_weight, "subsample": self.subsample, "colsample_bytree": self.colsample_bytree, "colsample_bylevel": self.colsample_bylevel, "reg_alpha": self.reg_alpha, "reg_lambda": self.reg_lambda, "scale_pos_weight": self.scale_pos_weight_, "gamma": self.gamma, "max_delta_step": self.max_delta_step, "tree_method": self.tree_method, "objective": self.objective, "n_jobs": self.n_jobs, "random_state": self.random_state, "verbosity": 2 if self.verbose else 0, } # 处理评估指标 wants_ks = False if metric_object is not None: params["eval_metric"] = metric_object.to_xgboost(api="sklearn", raw_score=callable(objective)) elif callable(eval_metric): params["eval_metric"] = eval_metric elif eval_metric is not None: if not isinstance(eval_metric, str) and any(isinstance(item, BaseMetric) for item in eval_metric): raise ValueError("XGBoost 的 eval_metric 请直接传入一个指标对象;多个指标可在训练后统一评估") converted_metrics = self._convert_metrics(eval_metric) metric_list = [converted_metrics] if isinstance(converted_metrics, str) else list(converted_metrics) wants_ks = any(str(metric).lower() == "ks" for metric in metric_list) native_metrics = [metric for metric in metric_list if str(metric).lower() != "ks"] if native_metrics: params["eval_metric"] = native_metrics[0] if isinstance(converted_metrics, str) else native_metrics # 处理早停参数(XGBoost 2.0+ 在构造函数中传入) callbacks = [] if wants_ks and eval_set: callbacks.append(self._create_ks_callback(eval_set)) if early_stopping_rounds is not None and eval_set: # 如果指定了早停指标,使用EarlyStopping回调 if self.early_stopping_metric is not None or metric_object is not None: try: from xgboost.callback import EarlyStopping callbacks.append( EarlyStopping( rounds=early_stopping_rounds, metric_name=self.early_stopping_metric or metric_object.name, data_name=self.early_stopping_data, save_best=True, maximize=( metric_object.greater_is_better if metric_object is not None and self.early_stopping_metric in (None, metric_object.name) else (True if str(self.early_stopping_metric).lower() == "ks" else None) ), ) ) if self.verbose: logger.info( f"使用早停: rounds={early_stopping_rounds}, " f"metric='{self.early_stopping_metric}'" ) except ImportError: # 回退到旧方式 params["early_stopping_rounds"] = early_stopping_rounds if self.verbose: logger.info(f"使用早停: rounds={early_stopping_rounds} (默认指标)") else: # 未指定早停指标,使用默认方式(第一个eval_metric) params["early_stopping_rounds"] = early_stopping_rounds if self.verbose: logger.info(f"使用早停: rounds={early_stopping_rounds} (默认使用第一个指标)") if callbacks: params["callbacks"] = callbacks # 更新kwargs参数 params.update(self.kwargs) # 最后更新原生params(优先级最高) params.update( { key: value for key, value in self._native_params.items() if key not in {"eval_metric", "early_stopping_rounds", "callbacks", "scale_pos_weight"} } ) user_callbacks = self._native_params.get("callbacks", self.kwargs.get("callbacks", [])) callbacks.extend(copy.deepcopy(list(user_callbacks or []))) callbacks.extend(copy.deepcopy(list(fit_params.pop("callbacks", []) or []))) if callbacks: params["callbacks"] = callbacks params["scale_pos_weight"] = self.scale_pos_weight_ # KS 的记录必须先于依赖它的早停,避免回调集合无序时随机报 KeyError。 if wants_ks and eval_set and early_stopping_rounds is not None: requested = [eval_metric] if isinstance(eval_metric, str) else list(eval_metric) selected = self.early_stopping_metric or requested[-1] if str(selected).lower() == "ks": stopper = xgb.callback.EarlyStopping( rounds=early_stopping_rounds, metric_name="ks", data_name=self.early_stopping_data, maximize=True, save_best=True, ) callbacks = [ callback for callback in callbacks if not isinstance(callback, (_KSEvaluationCallback, xgb.callback.EarlyStopping)) ] callbacks.append(_KSEvaluationCallback(eval_set, stopper)) params["callbacks"] = callbacks params.pop("early_stopping_rounds", None) params = self._resolve_native_aliases(params, self._parameter_aliases) # 解析自定义损失(BaseLoss 实例 -> sklearn 包装器可用的目标函数) # 旧版 sklearn 目标回调不传权重,已完成自动划分的训练权重作为兼容回退。 params["objective"] = resolve_custom_objective(params.get("objective"), sample_weight=sample_weight) # 旧版在 fit 接收早停和回调,新版在构造器接收。 from packaging.version import Version if Version(xgb.__version__) < Version("1.6"): for name in ("callbacks", "early_stopping_rounds", "eval_metric"): if name in params and name in inspect.signature(xgb.XGBClassifier.fit).parameters: fit_params[name] = params.pop(name) if callable(fit_params.get("eval_metric")): if metric_object is not None: fit_params["eval_metric"] = metric_object.to_xgboost( api="native", raw_score=callable(params.get("objective")) ) else: metric = fit_params["eval_metric"] fit_params["eval_metric"] = lambda prediction, data: ( metric.__name__, metric(data.get_label(), prediction), ) # 创建模型 self.native_params_ = dict(params) self._model = xgb.XGBClassifier(**params) # 训练 - fit时不传早停参数(已在构造函数中传入) fit_kwargs = dict(fit_params) if auto_eval_split: self._split_row_aligned_fit_param(fit_kwargs, "base_margin", "base_margin_eval_set") if sw_val is not None: fit_kwargs.setdefault("sample_weight_eval_set", [sw_val]) if eval_set: fit_kwargs["eval_set"] = eval_set if sample_weight is not None: fit_kwargs["sample_weight"] = sample_weight fit_kwargs.setdefault("verbose", self.verbose) # 执行训练 self._model.fit(X_train, y_train, **fit_kwargs) # 保存结果 self._best_iteration = getattr(self._model, "best_iteration", None) self._best_score = getattr(self._model, "best_score", None) self._evals_result = getattr(self._model, "evals_result_", {}) self._is_fitted = True self._fit_probability_scorecard(X, y, sample_weight=scorecard_sample_weight) return self
@property def best_iteration_(self): """最佳迭代次数.""" return self._best_iteration @property def best_score_(self): """最佳得分.""" return self._best_score def _ks_metric(self, y_pred, dtrain): """KS评估指标(用于XGBoost内部评估). 参考内部建模常用KS作为评估指标。 """ from sklearn.metrics import roc_curve y_true = dtrain.get_label() fpr, tpr, _ = roc_curve(y_true, y_pred, pos_label=1) ks = abs(tpr - fpr).max() return "KS", ks @staticmethod def _create_ks_callback(eval_set): """创建逐轮计算 KS 的 XGBoost 回调,支持与原生指标并存。""" return _KSEvaluationCallback(eval_set)
[文档] def predict(self, X: Union[np.ndarray, pd.DataFrame], **predict_params) -> np.ndarray: """预测类别标签. 支持传入包含target列的数据框(scorecardpipeline风格)。 基于 predict_proba 取阈值,确保自定义损失(原始分数输出)下也能返回正确类别。 """ self._require_fitted() if predict_params: return self._model.predict(self._prepare_data(X)[0], **predict_params) proba = self.predict_proba(X) indices = np.argmax(proba, axis=1) return np.asarray(self.classes_)[indices]
[文档] def predict_proba(self, X: Union[np.ndarray, pd.DataFrame], **predict_params) -> np.ndarray: """预测概率. 支持传入包含target列的数据框(scorecardpipeline风格)。 当使用自定义损失函数(objective 为可调用对象)时,XGBoost 返回的是 未经过链接函数转换的原始分数(raw margin,一维数组),此处自动应用 sigmoid 转换为概率并补齐为二维 (n_samples, 2) 输出,与内置目标保持一致。 """ self._require_fitted() X, _, _ = self._prepare_data(X, extract_target=True) proba = np.asarray(self._model.predict_proba(X, **predict_params)) # 自定义损失返回一维原始分数,应用 sigmoid 并补齐为两列概率 if proba.ndim == 1: p1 = 1.0 / (1.0 + np.exp(-proba)) proba = np.column_stack([1.0 - p1, p1]) return proba
[文档] def get_feature_importances(self, importance_type: str = "gain") -> pd.Series: """获取特征重要性. :param importance_type: 重要性类型,可选: - 'gain': 平均增益 (默认) - 'weight': 分裂次数 - 'cover': 平均覆盖度 - 'total_gain': 总增益 - 'total_cover': 总覆盖度 :return: 特征重要性Series """ self._require_fitted() booster = self._model.get_booster() scores = booster.get_score(importance_type=importance_type) names = booster.feature_names or [f"f{i}" for i in range(self.n_features_in_)] importances = np.array([scores.get(name, 0.0) for name in names]) # 创建Series importance_series = pd.Series(importances, index=self.feature_names_in_, name="importance").sort_values( ascending=False ) self._feature_importances = importance_series return importance_series
@property def feature_importances_(self) -> np.ndarray: """特征重要性属性 (兼容sklearn风格). 直接在包装类上暴露重要性,兼容sklearn RFE/SFS等组件的 importance_getter。 """ self._require_fitted() return np.asarray(self._model.feature_importances_)
[文档] def get_booster(self) -> "xgb.Booster": """获取底层XGBoost booster对象. :return: XGBoost Booster对象 """ self._require_fitted() return self._model.get_booster()
[文档] def plot_tree(self, num_trees: int = 0, **kwargs): """绘制树结构. :param num_trees: 树的索引 :param kwargs: 其他绘图参数 """ self._require_fitted() return xgb.plot_tree(self._model, num_trees=num_trees, **kwargs)
[文档] def plot_importance(self, max_num_features: int = 10, **kwargs): """绘制特征重要性. :param max_num_features: 显示的最大特征数 :param kwargs: 其他绘图参数 """ self._require_fitted() return xgb.plot_importance(self._model, max_num_features=max_num_features, **kwargs)
[文档] def get_leaf_indices(self, X: Union[np.ndarray, pd.DataFrame]) -> np.ndarray: """获取叶子节点索引. 返回每棵树上的叶子节点索引,用于GBDT+LR等场景。 :param X: 特征矩阵 :return: 叶子节点索引,形状 (n_samples, n_trees) **参考样例** >>> model = XGBoost(n_estimators=50) >>> model.fit(X, y) >>> leaf_indices = model.get_leaf_indices(X) >>> print(leaf_indices.shape) """ self._require_fitted() X = self._prepare_data(X)[0] return self._model.apply(X)
def _convert_metrics(self, metrics: Union[str, List[str]]) -> Union[str, List[str]]: """转换评估指标名称. :param metrics: 指标名称或列表 :return: XGBoost格式的指标名称 """ metric_map = { "auc": "auc", "logloss": "logloss", "error": "error", "rmse": "rmse", "mae": "mae", "map": "map", "merror": "merror", "mlogloss": "mlogloss", } if isinstance(metrics, str): return metric_map.get(metrics.lower(), metrics) return [metric_map.get(m.lower(), m) for m in metrics]
[文档] def save_model(self, path: str): """保存底层XGBoost模型(原生格式). :param path: 保存路径(.json/.ubj/.bin 格式) """ self._require_fitted() self._model.save_model(path) self._save_score_transformer_sidecar(path)
[文档] def load_model(self, path: str) -> "XGBoost": """加载底层XGBoost模型(原生格式). :param path: 模型路径 :return: self """ self._model = xgb.XGBClassifier() self._model.load_model(path) self._is_fitted = True self.classes_ = np.asarray(self._model.classes_) self.n_features_in_ = self._model.n_features_in_ names = self._model.get_booster().feature_names self._feature_names_known_ = names is not None self.feature_names_in_ = ( list(names) if names is not None else [f"feature_{i}" for i in range(self.n_features_in_)] ) self._load_score_transformer_sidecar(path) return self