diff --git a/python-package/xgboost/callback.py b/python-package/xgboost/callback.py index b8d5a751ed9b..35763a08b58a 100644 --- a/python-package/xgboost/callback.py +++ b/python-package/xgboost/callback.py @@ -23,7 +23,13 @@ import numpy from . import collective -from .core import Booster, DMatrix, XGBoostError, _parse_eval_str +from .core import ( + Booster, + DMatrix, + XGBoostError, + _deprecate_positional_args, + _parse_eval_str, +) __all__ = [ "TrainingCallback", @@ -346,8 +352,10 @@ class EarlyStopping(TrainingCallback): """ # pylint: disable=too-many-arguments + @_deprecate_positional_args def __init__( self, + *, rounds: int, metric_name: Optional[str] = None, data_name: Optional[str] = None, @@ -375,7 +383,7 @@ def before_training(self, model: _Model) -> _Model: return model def _update_rounds( - self, score: _Score, name: str, metric: str, model: _Model, epoch: int + self, *, score: _Score, name: str, metric: str, model: _Model, epoch: int ) -> bool: def get_s(value: _Score) -> float: """get score if it's cross validation history.""" @@ -471,7 +479,9 @@ def after_iteration( # The latest score score = data_log[metric_name][-1] - return self._update_rounds(score, data_name, metric_name, model, epoch) + return self._update_rounds( + score=score, name=data_name, metric=metric_name, model=model, epoch=epoch + ) def after_training(self, model: _Model) -> _Model: if not self.save_best: diff --git a/python-package/xgboost/core.py b/python-package/xgboost/core.py index 97242889af68..68a77eb31f1d 100644 --- a/python-package/xgboost/core.py +++ b/python-package/xgboost/core.py @@ -907,7 +907,7 @@ def __init__( return handle, feature_names, feature_types = dispatch_data_backend( - data, + data=data, missing=self.missing, threads=self.nthread, feature_names=feature_names, @@ -1697,6 +1697,7 @@ class ExtMemQuantileDMatrix(DMatrix): def __init__( # pylint: disable=super-init-not-called self, data: DataIter, + *, missing: Optional[float] = None, nthread: Optional[int] = None, max_bin: Optional[int] = None, @@ -2355,9 +2356,11 @@ def eval(self, data: DMatrix, name: str = "eval", iteration: int = 0) -> str: return self.eval_set([(data, name)], iteration) # pylint: disable=too-many-function-args + @_deprecate_positional_args def predict( self, data: DMatrix, + *, output_margin: bool = False, pred_leaf: bool = False, pred_contribs: bool = False, @@ -2490,9 +2493,11 @@ def assign_type(t: int) -> None: return _prediction_output(shape, dims, preds, False) # pylint: disable=too-many-statements + @_deprecate_positional_args def inplace_predict( self, data: DataType, + *, iteration_range: IterationRange = (0, 0), predict_type: str = "value", missing: float = np.nan, diff --git a/python-package/xgboost/dask/__init__.py b/python-package/xgboost/dask/__init__.py index a2edd26b9b5e..c51e6aec97e5 100644 --- a/python-package/xgboost/dask/__init__.py +++ b/python-package/xgboost/dask/__init__.py @@ -339,8 +339,8 @@ def __init__( self._init = client.sync( self._map_local_data, - client, - data, + client=client, + data=data, label=label, weights=weight, base_margin=base_margin, @@ -355,6 +355,7 @@ def __await__(self) -> Generator: async def _map_local_data( self, + *, client: "distributed.Client", data: _DataT, label: Optional[_DaskCollection] = None, @@ -589,6 +590,7 @@ def __init__( self, data: List[Any], label: Optional[List[Any]] = None, + *, weight: Optional[List[Any]] = None, base_margin: Optional[List[Any]] = None, qid: Optional[List[Any]] = None, @@ -712,6 +714,7 @@ def _create_fn_args(self, worker_addr: str) -> Dict[str, Any]: def _create_quantile_dmatrix( + *, feature_names: Optional[FeatureNames], feature_types: Optional[Union[Any, List[Any]]], feature_weights: Optional[Any], @@ -757,6 +760,7 @@ def _create_quantile_dmatrix( def _create_dmatrix( + *, feature_names: Optional[FeatureNames], feature_types: Optional[Union[Any, List[Any]]], feature_weights: Optional[Any], @@ -927,6 +931,7 @@ def _get_dmatrices( async def _train_async( + *, client: "distributed.Client", global_config: Dict[str, Any], dconfig: Optional[Dict[str, Any]], @@ -947,7 +952,7 @@ async def _train_async( _rabit_args = await _get_rabit_args(len(workers), dconfig, client) _check_distributed_params(params) - def dispatched_train( + def dispatched_train( # pylint: disable=too-many-positional-arguments parameters: Dict, rabit_args: Dict[str, Union[str, int]], train_id: int, @@ -1115,6 +1120,7 @@ def _maybe_dataframe( async def _direct_predict_impl( # pylint: disable=too-many-branches + *, mapped_predict: Callable, booster: "distributed.Future", data: _DataT, @@ -1249,6 +1255,7 @@ async def _predict_async( global_config: Dict[str, Any], model: Union[Booster, Dict, "distributed.Future"], data: _DataT, + *, output_margin: bool, missing: float, pred_leaf: bool, @@ -1304,7 +1311,12 @@ def mapped_predict( ) ) return await _direct_predict_impl( - mapped_predict, _booster, data, None, _output_shape, meta + mapped_predict=mapped_predict, + booster=_booster, + data=data, + base_margin=None, + output_shape=_output_shape, + meta=meta, ) output_shape, _ = await client.compute( @@ -1392,10 +1404,12 @@ def dispatched_predict(booster: Booster, part: Dict[str, Any]) -> numpy.ndarray: return predictions +@_deprecate_positional_args def predict( # pylint: disable=unused-argument client: Optional["distributed.Client"], model: Union[TrainReturnT, Booster, "distributed.Future"], data: Union[DaskDMatrix, _DataT], + *, output_margin: bool = False, missing: float = numpy.nan, pred_leaf: bool = False, @@ -1447,6 +1461,7 @@ def predict( # pylint: disable=unused-argument async def _inplace_predict_async( # pylint: disable=too-many-branches + *, client: "distributed.Client", global_config: Dict[str, Any], model: Union[Booster, Dict, "distributed.Future"], @@ -1501,14 +1516,21 @@ def mapped_predict( ) ) return await _direct_predict_impl( - mapped_predict, booster, data, base_margin, shape, meta + mapped_predict=mapped_predict, + booster=booster, + data=data, + base_margin=base_margin, + output_shape=shape, + meta=meta, ) +@_deprecate_positional_args def inplace_predict( # pylint: disable=unused-argument client: Optional["distributed.Client"], model: Union[TrainReturnT, Booster, "distributed.Future"], data: _DataT, + *, iteration_range: IterationRange = (0, 0), predict_type: str = "value", missing: float = numpy.nan, @@ -1615,6 +1637,7 @@ class DaskScikitLearnBase(XGBModel): async def _predict_async( self, data: _DataT, + *, output_margin: bool, validate_features: bool, base_margin: Optional[_DaskCollection], @@ -1652,9 +1675,11 @@ async def _predict_async( ) return predts + @_deprecate_positional_args def predict( self, X: _DataT, + *, output_margin: bool = False, validate_features: bool = True, base_margin: Optional[_DaskCollection] = None, @@ -1765,6 +1790,7 @@ async def _fit_async( self, X: _DataT, y: _DaskCollection, + *, sample_weight: Optional[_DaskCollection], base_margin: Optional[_DaskCollection], eval_set: Optional[Sequence[Tuple[_DaskCollection, _DaskCollection]]], @@ -1855,6 +1881,7 @@ async def _fit_async( self, X: _DataT, y: _DaskCollection, + *, sample_weight: Optional[_DaskCollection], base_margin: Optional[_DaskCollection], eval_set: Optional[Sequence[Tuple[_DaskCollection, _DaskCollection]]], @@ -1999,13 +2026,18 @@ def predict_proba( async def _predict_async( self, data: _DataT, + *, output_margin: bool, validate_features: bool, base_margin: Optional[_DaskCollection], iteration_range: Optional[IterationRange], ) -> _DaskCollection: pred_probs = await super()._predict_async( - data, output_margin, validate_features, base_margin, iteration_range + data, + output_margin=output_margin, + validate_features=validate_features, + base_margin=base_margin, + iteration_range=iteration_range, ) if output_margin: return pred_probs @@ -2049,6 +2081,7 @@ async def _fit_async( self, X: _DataT, y: _DaskCollection, + *, group: Optional[_DaskCollection], qid: Optional[_DaskCollection], sample_weight: Optional[_DaskCollection], diff --git a/python-package/xgboost/data.py b/python-package/xgboost/data.py index 22c447708813..820efe201757 100644 --- a/python-package/xgboost/data.py +++ b/python-package/xgboost/data.py @@ -128,6 +128,7 @@ def transform_scipy_sparse(data: DataType, is_csr: bool) -> DataType: def _from_scipy_csr( + *, data: DataType, missing: FloatCompatible, nthread: int, @@ -176,6 +177,7 @@ def is_scipy_csc(data: DataType) -> bool: def _from_scipy_csc( + *, data: DataType, missing: FloatCompatible, nthread: int, @@ -251,6 +253,7 @@ def _maybe_np_slice(data: DataType, dtype: Optional[NumpyDType]) -> np.ndarray: def _from_numpy_array( + *, data: np.ndarray, missing: FloatCompatible, nthread: int, @@ -639,6 +642,7 @@ def _meta_from_pandas_df( def _from_pandas_df( + *, data: DataFrame, enable_categorical: bool, missing: FloatCompatible, @@ -698,6 +702,7 @@ def _is_modin_series(data: DataType) -> bool: def _from_pandas_series( + *, data: DataType, missing: FloatCompatible, nthread: int, @@ -712,11 +717,11 @@ def _from_pandas_series( if enable_categorical and is_pd_cat_dtype(data.dtype): data = data.cat.codes return _from_numpy_array( - data.values.reshape(data.shape[0], 1).astype("float"), - missing, - nthread, - feature_names, - feature_types, + data=data.values.reshape(data.shape[0], 1).astype("float"), + missing=missing, + nthread=nthread, + feature_names=feature_names, + feature_types=feature_types, ) @@ -768,6 +773,7 @@ def _transform_dt_df( def _from_dt_df( + *, data: DataType, missing: Optional[FloatCompatible], nthread: int, @@ -778,7 +784,11 @@ def _from_dt_df( if enable_categorical: raise ValueError("categorical data in datatable is not supported yet.") data, feature_names, feature_types = _transform_dt_df( - data, feature_names, feature_types, None, None + data=data, + feature_names=feature_names, + feature_types=feature_types, + meta=None, + meta_type=None, ) ptrs = (ctypes.c_void_p * data.ncols)() @@ -968,6 +978,7 @@ def _transform_cudf_df( def _from_cudf_df( + *, data: DataType, missing: FloatCompatible, nthread: int, @@ -1095,6 +1106,7 @@ def _is_list(data: DataType) -> TypeGuard[list]: def _from_list( + *, data: Sequence, missing: FloatCompatible, n_threads: int, @@ -1105,7 +1117,12 @@ def _from_list( array = np.array(data) _check_data_shape(data) return _from_numpy_array( - array, missing, n_threads, feature_names, feature_types, data_split_mode + data=array, + missing=missing, + nthread=n_threads, + feature_names=feature_names, + feature_types=feature_types, + data_split_mode=data_split_mode, ) @@ -1114,6 +1131,7 @@ def _is_tuple(data: DataType) -> TypeGuard[tuple]: def _from_tuple( + *, data: Sequence, missing: FloatCompatible, n_threads: int, @@ -1122,7 +1140,12 @@ def _from_tuple( data_split_mode: DataSplitMode = DataSplitMode.ROW, ) -> DispatchedDataBackendReturnType: return _from_list( - data, missing, n_threads, feature_names, feature_types, data_split_mode + data=data, + missing=missing, + n_threads=n_threads, + feature_names=feature_names, + feature_types=feature_types, + data_split_mode=data_split_mode, ) @@ -1153,6 +1176,7 @@ def _convert_unknown_data(data: DataType) -> DataType: def dispatch_data_backend( + *, data: DataType, missing: FloatCompatible, # Or Optional[Float] threads: int, @@ -1166,34 +1190,59 @@ def dispatch_data_backend( _check_data_shape(data) if is_scipy_csr(data): return _from_scipy_csr( - data, missing, threads, feature_names, feature_types, data_split_mode + data=data, + missing=missing, + nthread=threads, + feature_names=feature_names, + feature_types=feature_types, + data_split_mode=data_split_mode, ) if is_scipy_csc(data): return _from_scipy_csc( - data, missing, threads, feature_names, feature_types, data_split_mode + data=data, + missing=missing, + nthread=threads, + feature_names=feature_names, + feature_types=feature_types, + data_split_mode=data_split_mode, ) if is_scipy_coo(data): return _from_scipy_csr( - data.tocsr(), - missing, - threads, - feature_names, - feature_types, - data_split_mode, + data=data.tocsr(), + missing=missing, + nthread=threads, + feature_names=feature_names, + feature_types=feature_types, + data_split_mode=data_split_mode, ) if _is_np_array_like(data): return _from_numpy_array( - data, missing, threads, feature_names, feature_types, data_split_mode + data=data, + missing=missing, + nthread=threads, + feature_names=feature_names, + feature_types=feature_types, + data_split_mode=data_split_mode, ) if _is_uri(data): return _from_uri(data, missing, feature_names, feature_types, data_split_mode) if _is_list(data): return _from_list( - data, missing, threads, feature_names, feature_types, data_split_mode + data=data, + missing=missing, + n_threads=threads, + feature_names=feature_names, + feature_types=feature_types, + data_split_mode=data_split_mode, ) if _is_tuple(data): return _from_tuple( - data, missing, threads, feature_names, feature_types, data_split_mode + data=data, + missing=missing, + n_threads=threads, + feature_names=feature_names, + feature_types=feature_types, + data_split_mode=data_split_mode, ) if _is_arrow(data): data = _arrow_transform(data) @@ -1203,17 +1252,22 @@ def dispatch_data_backend( data = pd.DataFrame(data) if _is_pandas_df(data): return _from_pandas_df( - data, - enable_categorical, - missing, - threads, - feature_names, - feature_types, - data_split_mode, + data=data, + enable_categorical=enable_categorical, + missing=missing, + nthread=threads, + feature_names=feature_names, + feature_types=feature_types, + data_split_mode=data_split_mode, ) if _is_cudf_df(data) or _is_cudf_ser(data): return _from_cudf_df( - data, missing, threads, feature_names, feature_types, enable_categorical + data=data, + missing=missing, + nthread=threads, + feature_names=feature_names, + feature_types=feature_types, + enable_categorical=enable_categorical, ) if _is_cupy_alike(data): return _from_cupy_array(data, missing, threads, feature_names, feature_types) @@ -1226,24 +1280,49 @@ def dispatch_data_backend( if _is_dt_df(data): _warn_unused_missing(data, missing) return _from_dt_df( - data, missing, threads, feature_names, feature_types, enable_categorical + data=data, + missing=missing, + nthread=threads, + feature_names=feature_names, + feature_types=feature_types, + enable_categorical=enable_categorical, ) if _is_modin_df(data): return _from_pandas_df( - data, enable_categorical, missing, threads, feature_names, feature_types + data=data, + enable_categorical=enable_categorical, + missing=missing, + nthread=threads, + feature_names=feature_names, + feature_types=feature_types, ) if _is_modin_series(data): return _from_pandas_series( - data, missing, threads, enable_categorical, feature_names, feature_types + data=data, + missing=missing, + nthread=threads, + enable_categorical=enable_categorical, + feature_names=feature_names, + feature_types=feature_types, ) if _has_array_protocol(data): array = np.asarray(data) - return _from_numpy_array(array, missing, threads, feature_names, feature_types) + return _from_numpy_array( + data=array, + missing=missing, + nthread=threads, + feature_names=feature_names, + feature_types=feature_types, + ) converted = _convert_unknown_data(data) if converted is not None: return _from_scipy_csr( - converted, missing, threads, feature_names, feature_types + data=converted, + missing=missing, + nthread=threads, + feature_names=feature_names, + feature_types=feature_types, ) raise TypeError("Not supported type for data." + str(type(data))) @@ -1313,7 +1392,9 @@ def _meta_from_cupy_array(data: DataType, field: str, handle: ctypes.c_void_p) - def _meta_from_dt( data: DataType, field: str, dtype: Optional[NumpyDType], handle: ctypes.c_void_p ) -> None: - data, _, _ = _transform_dt_df(data, None, None, field, dtype) + data, _, _ = _transform_dt_df( + data=data, feature_names=None, feature_types=None, meta=field, meta_type=dtype + ) _meta_from_numpy(data, field, dtype, handle) diff --git a/python-package/xgboost/federated.py b/python-package/xgboost/federated.py index 71db5a1c0345..e903d475cfc6 100644 --- a/python-package/xgboost/federated.py +++ b/python-package/xgboost/federated.py @@ -4,7 +4,7 @@ from threading import Thread from typing import Any, Dict, Optional -from .core import _LIB, _check_call, make_jcargs +from .core import _LIB, _check_call, _deprecate_positional_args, make_jcargs from .tracker import RabitTracker @@ -34,10 +34,12 @@ class FederatedTracker(RabitTracker): """ + @_deprecate_positional_args def __init__( # pylint: disable=R0913, W0231 self, n_workers: int, port: int, + *, secure: bool, server_key_path: Optional[str] = None, server_cert_path: Optional[str] = None, @@ -59,9 +61,11 @@ def __init__( # pylint: disable=R0913, W0231 self.handle = handle +@_deprecate_positional_args def run_federated_server( # pylint: disable=too-many-arguments n_workers: int, port: int, + *, server_key_path: Optional[str] = None, server_cert_path: Optional[str] = None, client_cert_path: Optional[str] = None, diff --git a/python-package/xgboost/plotting.py b/python-package/xgboost/plotting.py index d9eb14d0f600..07009f8be920 100644 --- a/python-package/xgboost/plotting.py +++ b/python-package/xgboost/plotting.py @@ -8,15 +8,17 @@ import numpy as np from ._typing import PathLike -from .core import Booster +from .core import Booster, _deprecate_positional_args from .sklearn import XGBModel Axes = Any # real type is matplotlib.axes.Axes GraphvizSource = Any # real type is graphviz.Source +@_deprecate_positional_args def plot_importance( booster: Union[XGBModel, Booster, dict], + *, ax: Optional[Axes] = None, height: float = 0.2, xlim: Optional[tuple] = None, @@ -146,8 +148,10 @@ def plot_importance( return ax +@_deprecate_positional_args def to_graphviz( booster: Union[Booster, XGBModel], + *, fmap: PathLike = "", num_trees: int = 0, rankdir: Optional[str] = None, diff --git a/python-package/xgboost/sklearn.py b/python-package/xgboost/sklearn.py index 45a1d4b6796a..63448bf1458d 100644 --- a/python-package/xgboost/sklearn.py +++ b/python-package/xgboost/sklearn.py @@ -582,6 +582,7 @@ def adddoc(cls: Type) -> Type: def _wrap_evaluation_matrices( + *, missing: float, X: Any, y: Any, @@ -696,8 +697,10 @@ def validate_or_none(meta: Optional[Sequence], name: str) -> Sequence: ) class XGBModel(XGBModelBase): # pylint: disable=too-many-arguments, too-many-instance-attributes, missing-docstring + @_deprecate_positional_args def __init__( self, + *, max_depth: Optional[int] = None, max_leaves: Optional[int] = None, max_bin: Optional[int] = None, @@ -1174,9 +1177,11 @@ def _get_iteration_range( iteration_range = (0, 0) return iteration_range + @_deprecate_positional_args def predict( self, X: ArrayLike, + *, output_margin: bool = False, validate_features: bool = True, base_margin: Optional[ArrayLike] = None, @@ -1587,9 +1592,11 @@ def fit( "Fit gradient boosting model", "Fit gradient boosting classifier", 1 ) + @_deprecate_positional_args def predict( self, X: ArrayLike, + *, output_margin: bool = False, validate_features: bool = True, base_margin: Optional[ArrayLike] = None, @@ -2070,9 +2077,11 @@ def fit( self._set_evaluation_result(evals_result) return self + @_deprecate_positional_args def predict( self, X: ArrayLike, + *, output_margin: bool = False, validate_features: bool = True, base_margin: Optional[ArrayLike] = None, @@ -2081,9 +2090,9 @@ def predict( X, _ = _get_qid(X, None) return super().predict( X, - output_margin, - validate_features, - base_margin, + output_margin=output_margin, + validate_features=validate_features, + base_margin=base_margin, iteration_range=iteration_range, ) diff --git a/python-package/xgboost/spark/core.py b/python-package/xgboost/spark/core.py index 7eef43842459..e183983ef915 100644 --- a/python-package/xgboost/spark/core.py +++ b/python-package/xgboost/spark/core.py @@ -1072,11 +1072,11 @@ def _train_booster( with CommunicatorContext(context, **_rabit_args): with xgboost.config_context(verbosity=verbosity): dtrain, dvalid = create_dmatrix_from_partitions( - pandas_df_iter, - feature_prop.features_cols_names, - dev_ordinal, - use_qdm, - dmatrix_kwargs, + iterator=pandas_df_iter, + feature_cols=feature_prop.features_cols_names, + dev_ordinal=dev_ordinal, + use_qdm=use_qdm, + kwargs=dmatrix_kwargs, enable_sparse_data_optim=feature_prop.enable_sparse_data_optim, has_validation_col=feature_prop.has_validation_col, ) diff --git a/python-package/xgboost/spark/data.py b/python-package/xgboost/spark/data.py index 9c21f6ae8577..99fdffbb9942 100644 --- a/python-package/xgboost/spark/data.py +++ b/python-package/xgboost/spark/data.py @@ -171,6 +171,7 @@ def make_qdm( def create_dmatrix_from_partitions( # pylint: disable=too-many-arguments + *, iterator: Iterator[pd.DataFrame], feature_cols: Optional[Sequence[str]], dev_ordinal: Optional[int], diff --git a/python-package/xgboost/testing/__init__.py b/python-package/xgboost/testing/__init__.py index 0bc17c052e0e..dd0a44bb3172 100644 --- a/python-package/xgboost/testing/__init__.py +++ b/python-package/xgboost/testing/__init__.py @@ -224,6 +224,7 @@ def __init__( # pylint: disable=too-many-arguments X: Sequence, y: Sequence, w: Optional[Sequence], + *, cache: Optional[str], on_host: bool = False, ) -> None: @@ -379,6 +380,7 @@ def make_categorical( n_samples: int, n_features: int, n_categories: int, + *, onehot: bool, sparsity: float = 0.0, cat_ratio: float = 1.0, @@ -487,7 +489,9 @@ def _build(args: Tuple[int, int, int, float]) -> TestDataset: sparsity = args[3] return TestDataset( f"{n_samples}x{n_features}-{n_cats}-{sparsity}", - lambda: make_categorical(n_samples, n_features, n_cats, False, sparsity), + lambda: make_categorical( + n_samples, n_features, n_cats, onehot=False, sparsity=sparsity + ), "reg:squarederror", "rmse", ) diff --git a/python-package/xgboost/testing/data_iter.py b/python-package/xgboost/testing/data_iter.py index f51b303d5da8..e107557d3049 100644 --- a/python-package/xgboost/testing/data_iter.py +++ b/python-package/xgboost/testing/data_iter.py @@ -22,7 +22,7 @@ def run_mixed_sparsity(device: str) -> None: X = [cp.array(batch) for batch in X] - it = tm.IteratorForTest(X, y, None, None, on_host=False) + it = tm.IteratorForTest(X, y, None, cache=None, on_host=False) Xy_0 = xgboost.QuantileDMatrix(it) X_1, y_1 = tm.make_sparse_regression(256, 16, 0.1, True) diff --git a/python-package/xgboost/testing/shared.py b/python-package/xgboost/testing/shared.py index 0455b77d046b..46e4feacc93d 100644 --- a/python-package/xgboost/testing/shared.py +++ b/python-package/xgboost/testing/shared.py @@ -52,6 +52,7 @@ def new_init(self: Any, **kwargs: Any) -> Callable: # pylint: disable=too-many-arguments,too-many-locals def get_feature_weights( + *, X: ArrayLike, y: ArrayLike, fw: np.ndarray, diff --git a/python-package/xgboost/testing/updater.py b/python-package/xgboost/testing/updater.py index 0db91491ee27..8b8da6da8805 100644 --- a/python-package/xgboost/testing/updater.py +++ b/python-package/xgboost/testing/updater.py @@ -291,7 +291,9 @@ def check_get_quantile_cut_device(tree_method: str, use_cupy: bool) -> None: # categorical n_categories = 32 - X, y = tm.make_categorical(n_samples, n_features, n_categories, False, sparsity=0.8) + X, y = tm.make_categorical( + n_samples, n_features, n_categories, onehot=False, sparsity=0.8 + ) if use_cupy: import cudf # pylint: disable=import-error import cupy as cp # pylint: disable=import-error @@ -310,7 +312,7 @@ def check_get_quantile_cut_device(tree_method: str, use_cupy: bool) -> None: # mixed X, y = tm.make_categorical( - n_samples, n_features, n_categories, False, sparsity=0.8, cat_ratio=0.5 + n_samples, n_features, n_categories, onehot=False, sparsity=0.8, cat_ratio=0.5 ) n_cat_features = len([0 for dtype in X.dtypes if is_pd_cat_dtype(dtype)]) n_num_features = n_features - n_cat_features @@ -340,12 +342,12 @@ def check_get_quantile_cut(tree_method: str, device: str) -> None: def check_categorical_ohe( # pylint: disable=too-many-arguments - rows: int, cols: int, rounds: int, cats: int, device: str, tree_method: str + *, rows: int, cols: int, rounds: int, cats: int, device: str, tree_method: str ) -> None: "Test for one-hot encoding with categorical data." - onehot, label = tm.make_categorical(rows, cols, cats, True) - cat, _ = tm.make_categorical(rows, cols, cats, False) + onehot, label = tm.make_categorical(rows, cols, cats, onehot=True) + cat, _ = tm.make_categorical(rows, cols, cats, onehot=False) by_etl_results: Dict[str, Dict[str, List[float]]] = {} by_builtin_results: Dict[str, Dict[str, List[float]]] = {} diff --git a/python-package/xgboost/tracker.py b/python-package/xgboost/tracker.py index d88b2564054b..ab47b6b0d769 100644 --- a/python-package/xgboost/tracker.py +++ b/python-package/xgboost/tracker.py @@ -6,7 +6,7 @@ from enum import IntEnum, unique from typing import Dict, Optional, Union -from .core import _LIB, _check_call, make_jcargs +from .core import _LIB, _check_call, _deprecate_positional_args, make_jcargs def get_family(addr: str) -> int: @@ -48,11 +48,13 @@ class _SortBy(IntEnum): HOST = 0 TASK = 1 + @_deprecate_positional_args def __init__( # pylint: disable=too-many-arguments self, n_workers: int, host_ip: Optional[str], port: int = 0, + *, sortby: str = "host", timeout: int = 0, ) -> None: diff --git a/python-package/xgboost/training.py b/python-package/xgboost/training.py index 3c82289303d2..bb4ebe44e1ed 100644 --- a/python-package/xgboost/training.py +++ b/python-package/xgboost/training.py @@ -288,6 +288,7 @@ def groups_to_rows(groups: np.ndarray, boundaries: np.ndarray) -> np.ndarray: def mkgroupfold( + *, dall: DMatrix, nfold: int, param: BoosterParam, @@ -341,6 +342,7 @@ def mkgroupfold( def mknfold( + *, dall: DMatrix, nfold: int, param: BoosterParam, @@ -361,7 +363,12 @@ def mknfold( # Do standard k-fold cross validation. Automatically determine the folds. if len(dall.get_uint_info("group_ptr")) > 1: return mkgroupfold( - dall, nfold, param, evals=evals, fpreproc=fpreproc, shuffle=shuffle + dall=dall, + nfold=nfold, + param=param, + evals=evals, + fpreproc=fpreproc, + shuffle=shuffle, ) if shuffle is True: @@ -407,10 +414,12 @@ def mknfold( return ret +@_deprecate_positional_args def cv( params: BoosterParam, dtrain: DMatrix, num_boost_round: int = 10, + *, nfold: int = 3, stratified: bool = False, folds: XGBStratifiedKFold = None, @@ -541,7 +550,15 @@ def cv( results: Dict[str, List[float]] = {} cvfolds = mknfold( - dtrain, nfold, params, seed, metrics, fpreproc, stratified, folds, shuffle + dall=dtrain, + nfold=nfold, + param=params, + seed=seed, + evals=metrics, + fpreproc=fpreproc, + stratified=stratified, + folds=folds, + shuffle=shuffle, ) metric_fn = _configure_custom_metric(feval, custom_metric) diff --git a/tests/ci_build/lint_python.py b/tests/ci_build/lint_python.py index d2573e6f4915..91302c1ed563 100644 --- a/tests/ci_build/lint_python.py +++ b/tests/ci_build/lint_python.py @@ -32,6 +32,7 @@ class LintersPaths: "tests/python/test_tree_regularization.py", "tests/python/test_training_continuation.py", "tests/python/test_shap.py", + "tests/python/test_updaters.py", "tests/python/test_model_io.py", "tests/python/test_with_pandas.py", "tests/python-gpu/", diff --git a/tests/python-gpu/test_from_cudf.py b/tests/python-gpu/test_from_cudf.py index fd7c9d745db0..37826f35cc34 100644 --- a/tests/python-gpu/test_from_cudf.py +++ b/tests/python-gpu/test_from_cudf.py @@ -195,7 +195,7 @@ def test_cudf_metainfo_device_dmatrix(self): @pytest.mark.skipif(**tm.no_cudf()) def test_cudf_categorical(self) -> None: n_features = 30 - _X, _y = tm.make_categorical(100, n_features, 17, False) + _X, _y = tm.make_categorical(100, n_features, 17, onehot=False) X = cudf.from_pandas(_X) y = cudf.from_pandas(_y) @@ -312,7 +312,7 @@ def __init__(self, categorical): self._data = [] self._labels = [] for i in range(self.BATCHES): - X, y = tm.make_categorical(self.ROWS_PER_BATCH, 4, 13, False) + X, y = tm.make_categorical(self.ROWS_PER_BATCH, 4, 13, onehot=False) self._data.append(cudf.from_pandas(X)) self._labels.append(y) else: diff --git a/tests/python-gpu/test_gpu_prediction.py b/tests/python-gpu/test_gpu_prediction.py index b3ccf4ae5e98..ea9dade9673e 100644 --- a/tests/python-gpu/test_gpu_prediction.py +++ b/tests/python-gpu/test_gpu_prediction.py @@ -405,7 +405,7 @@ def test_shap_interactions( ) def test_shap_categorical(self): - X, y = tm.make_categorical(100, 20, 7, False) + X, y = tm.make_categorical(100, 20, 7, onehot=False) Xy = xgb.DMatrix(X, y, enable_categorical=True) booster = xgb.train( {"tree_method": "hist", "device": "gpu:0"}, Xy, num_boost_round=10 diff --git a/tests/python-gpu/test_gpu_updaters.py b/tests/python-gpu/test_gpu_updaters.py index 21f7f76fed5d..5d7710b3ae9f 100644 --- a/tests/python-gpu/test_gpu_updaters.py +++ b/tests/python-gpu/test_gpu_updaters.py @@ -140,7 +140,14 @@ def test_sparse(self, dataset): @settings(deadline=None, max_examples=20, print_blob=True) @pytest.mark.skipif(**tm.no_pandas()) def test_categorical_ohe(self, rows, cols, rounds, cats): - check_categorical_ohe(rows, cols, rounds, cats, "cuda", "hist") + check_categorical_ohe( + rows=rows, + cols=cols, + rounds=rounds, + cats=cats, + device="cuda", + tree_method="hist", + ) @given( tm.categorical_dataset_strategy, @@ -222,10 +229,9 @@ def test_max_cat(self) -> None: def test_categorical_32_cat(self): """32 hits the bound of integer bitset, so special test""" rows = 1000 - cols = 10 - cats = 32 - rounds = 4 - check_categorical_ohe(rows, cols, rounds, cats, "cuda", "hist") + check_categorical_ohe( + rows=rows, cols=10, rounds=4, cats=32, device="cuda", tree_method="hist" + ) @pytest.mark.skipif(**tm.no_cupy()) def test_invalid_category(self): diff --git a/tests/python/test_model_io.py b/tests/python/test_model_io.py index 37b3aac35bfc..65e85550944c 100644 --- a/tests/python/test_model_io.py +++ b/tests/python/test_model_io.py @@ -104,7 +104,7 @@ def test_model_json_io(self, ext: str) -> None: self.run_model_json_io(parameters, ext) def test_categorical_model_io(self) -> None: - X, y = tm.make_categorical(256, 16, 71, False) + X, y = tm.make_categorical(256, 16, 71, onehot=False) Xy = xgb.DMatrix(X, y, enable_categorical=True) booster = xgb.train({"tree_method": "approx"}, Xy, num_boost_round=16) predt_0 = booster.predict(Xy) diff --git a/tests/python/test_parse_tree.py b/tests/python/test_parse_tree.py index 9d80d0f6fd30..1be6c1d3ba92 100644 --- a/tests/python/test_parse_tree.py +++ b/tests/python/test_parse_tree.py @@ -49,7 +49,7 @@ def test_trees_to_dataframe(self): assert np.allclose(cover_from_dump, cover_from_df) def run_tree_to_df_categorical(self, tree_method: str) -> None: - X, y = tm.make_categorical(100, 10, 31, False) + X, y = tm.make_categorical(100, 10, 31, onehot=False) Xy = xgb.DMatrix(X, y, enable_categorical=True) booster = xgb.train({"tree_method": tree_method}, Xy, num_boost_round=10) df = booster.trees_to_dataframe() @@ -61,7 +61,7 @@ def test_tree_to_df_categorical(self) -> None: self.run_tree_to_df_categorical("approx") def run_split_value_histograms(self, tree_method) -> None: - X, y = tm.make_categorical(1000, 10, 13, False) + X, y = tm.make_categorical(1000, 10, 13, onehot=False) reg = xgb.XGBRegressor(tree_method=tree_method, enable_categorical=True) reg.fit(X, y) diff --git a/tests/python/test_quantile_dmatrix.py b/tests/python/test_quantile_dmatrix.py index 7d06d8608cae..19bce7317c66 100644 --- a/tests/python/test_quantile_dmatrix.py +++ b/tests/python/test_quantile_dmatrix.py @@ -97,14 +97,15 @@ def test_with_iterator(self, sparsity: float) -> None: if sparsity == 0.0: it = IteratorForTest( - *make_batches(n_samples_per_batch, n_features, n_batches, False), None + *make_batches(n_samples_per_batch, n_features, n_batches, False), + cache=None, ) else: it = IteratorForTest( *make_batches_sparse( n_samples_per_batch, n_features, n_batches, sparsity ), - None, + cache=None, ) Xy = xgb.QuantileDMatrix(it) assert Xy.num_row() == n_samples_per_batch * n_batches @@ -134,14 +135,15 @@ def test_training(self, sparsity: float) -> None: n_batches = 7 if sparsity == 0.0: it = IteratorForTest( - *make_batches(n_samples_per_batch, n_features, n_batches, False), None + *make_batches(n_samples_per_batch, n_features, n_batches, False), + cache=None, ) else: it = IteratorForTest( *make_batches_sparse( n_samples_per_batch, n_features, n_batches, sparsity ), - None, + cache=None, ) parameters = {"tree_method": "hist", "max_bin": 256} diff --git a/tests/python/test_updaters.py b/tests/python/test_updaters.py index f4de8896866b..95e5627242aa 100644 --- a/tests/python/test_updaters.py +++ b/tests/python/test_updaters.py @@ -81,23 +81,26 @@ def test_approx( @pytest.mark.skipif(**tm.no_sklearn()) def test_pruner(self): import sklearn - params = {'tree_method': 'exact'} + + params = {"tree_method": "exact"} cancer = sklearn.datasets.load_breast_cancer() - X = cancer['data'] + X = cancer["data"] y = cancer["target"] dtrain = xgb.DMatrix(X, y) booster = xgb.train(params, dtrain=dtrain, num_boost_round=10) grown = str(booster.get_dump()) - params = {'updater': 'prune', 'process_type': 'update', 'gamma': '0.2'} - booster = xgb.train(params, dtrain=dtrain, num_boost_round=10, - xgb_model=booster) + params = {"updater": "prune", "process_type": "update", "gamma": "0.2"} + booster = xgb.train( + params, dtrain=dtrain, num_boost_round=10, xgb_model=booster + ) after_prune = str(booster.get_dump()) assert grown != after_prune - booster = xgb.train(params, dtrain=dtrain, num_boost_round=10, - xgb_model=booster) + booster = xgb.train( + params, dtrain=dtrain, num_boost_round=10, xgb_model=booster + ) second_prune = str(booster.get_dump()) # Second prune should not change the tree assert after_prune == second_prune @@ -107,11 +110,12 @@ def test_pruner(self): hist_parameter_strategy, hist_cache_strategy, strategies.integers(1, 20), - tm.make_dataset_strategy() + tm.make_dataset_strategy(), ) @settings(deadline=None, print_blob=True) def test_hist( - self, param: Dict[str, Any], + self, + param: Dict[str, Any], hist_param: Dict[str, Any], cache_param: Dict[str, Any], num_rounds: int, @@ -128,11 +132,13 @@ def test_hist( def test_hist_categorical(self): # hist must be same as exact on all-categorial data ag_dtrain, ag_dtest = tm.load_agaricus(__file__) - ag_param = {'max_depth': 2, - 'tree_method': 'hist', - 'eta': 1, - 'objective': 'binary:logistic', - 'eval_metric': 'auc'} + ag_param = { + "max_depth": 2, + "tree_method": "hist", + "eta": 1, + "objective": "binary:logistic", + "eval_metric": "auc", + } hist_res = {} exact_res = {} @@ -141,7 +147,7 @@ def test_hist_categorical(self): ag_dtrain, 10, evals=[(ag_dtrain, "train"), (ag_dtest, "test")], - evals_result=hist_res + evals_result=hist_res, ) ag_param["tree_method"] = "exact" xgb.train( @@ -149,10 +155,10 @@ def test_hist_categorical(self): ag_dtrain, 10, evals=[(ag_dtrain, "train"), (ag_dtest, "test")], - evals_result=exact_res + evals_result=exact_res, ) - assert hist_res['train']['auc'] == exact_res['train']['auc'] - assert hist_res['test']['auc'] == exact_res['test']['auc'] + assert hist_res["train"]["auc"] == exact_res["train"]["auc"] + assert hist_res["test"]["auc"] == exact_res["test"]["auc"] @pytest.mark.skipif(**tm.no_sklearn()) def test_hist_degenerate_case(self): @@ -160,11 +166,17 @@ def test_hist_degenerate_case(self): # quantile points for a particular feature (the second feature in # this example). Source: https://github.com/dmlc/xgboost/issues/2943 nan = np.nan - param = {'missing': nan, 'tree_method': 'hist'} + param = {"missing": nan, "tree_method": "hist"} model = xgb.XGBRegressor(**param) - X = np.array([[6.18827160e+05, 1.73000000e+02], [6.37345679e+05, nan], - [6.38888889e+05, nan], [6.28086420e+05, nan]]) - y = [1000000., 0., 0., 500000.] + X = np.array( + [ + [6.18827160e05, 1.73000000e02], + [6.37345679e05, nan], + [6.38888889e05, nan], + [6.28086420e05, nan], + ] + ) + y = [1000000.0, 0.0, 0.0, 500000.0] w = [0, 0, 1, 0] model.fit(X, y, sample_weight=w) @@ -174,12 +186,12 @@ def test_sparse(self, dataset): param = {"tree_method": "hist", "max_bin": 64} hist_result = train_result(param, dataset.get_dmat(), 16) note(str(hist_result)) - assert tm.non_increasing(hist_result['train'][dataset.metric]) + assert tm.non_increasing(hist_result["train"][dataset.metric]) param = {"tree_method": "approx", "max_bin": 64} approx_result = train_result(param, dataset.get_dmat(), 16) note(str(approx_result)) - assert tm.non_increasing(approx_result['train'][dataset.metric]) + assert tm.non_increasing(approx_result["train"][dataset.metric]) np.testing.assert_allclose( hist_result["train"]["rmse"], approx_result["train"]["rmse"] @@ -248,15 +260,33 @@ def run_max_cat(self, tree_method: str) -> None: def test_max_cat(self, tree_method) -> None: self.run_max_cat(tree_method) - @given(strategies.integers(10, 400), strategies.integers(3, 8), - strategies.integers(1, 2), strategies.integers(4, 7)) + @given( + strategies.integers(10, 400), + strategies.integers(3, 8), + strategies.integers(1, 2), + strategies.integers(4, 7), + ) @settings(deadline=None, print_blob=True) @pytest.mark.skipif(**tm.no_pandas()) def test_categorical_ohe( self, rows: int, cols: int, rounds: int, cats: int ) -> None: - check_categorical_ohe(rows, cols, rounds, cats, "cpu", "approx") - check_categorical_ohe(rows, cols, rounds, cats, "cpu", "hist") + check_categorical_ohe( + rows=rows, + cols=cols, + rounds=rounds, + cats=cats, + device="cpu", + tree_method="approx", + ) + check_categorical_ohe( + rows=rows, + cols=cols, + rounds=rounds, + cats=cats, + device="cpu", + tree_method="hist", + ) @given( tm.categorical_dataset_strategy, @@ -307,7 +337,7 @@ def test_categorical_ames_housing( @given( strategies.integers(10, 400), strategies.integers(3, 8), - strategies.integers(4, 7) + strategies.integers(4, 7), ) @settings(deadline=None, print_blob=True) @pytest.mark.skipif(**tm.no_pandas()) @@ -395,9 +425,8 @@ def get_score(config: Dict) -> float: @pytest.mark.skipif(**tm.no_sklearn()) @pytest.mark.parametrize( - "tree_method,weighted", [ - ("approx", False), ("hist", False), ("approx", True), ("hist", True) - ] + "tree_method,weighted", + [("approx", False), ("hist", False), ("approx", True), ("hist", True)], ) def test_adaptive(self, tree_method, weighted) -> None: self.run_adaptive(tree_method, weighted) diff --git a/tests/python/test_with_sklearn.py b/tests/python/test_with_sklearn.py index bea201cafe45..73102bf5c03c 100644 --- a/tests/python/test_with_sklearn.py +++ b/tests/python/test_with_sklearn.py @@ -1161,14 +1161,24 @@ def test_feature_weights(tree_method): parser_path = os.path.join(tm.demo_dir(__file__), "json-model", "json_parser.py") poly_increasing = get_feature_weights( - X, y, fw, parser_path, tree_method, xgb.XGBRegressor + X=X, + y=y, + fw=fw, + parser_path=parser_path, + tree_method=tree_method, + model=xgb.XGBRegressor, ) fw = np.ones(shape=(kCols,)) for i in range(kCols): fw[i] *= float(kCols - i) poly_decreasing = get_feature_weights( - X, y, fw, parser_path, tree_method, xgb.XGBRegressor + X=X, + y=y, + fw=fw, + parser_path=parser_path, + tree_method=tree_method, + model=xgb.XGBRegressor, ) # Approxmated test, this is dependent on the implementation of random diff --git a/tests/test_distributed/test_with_dask/test_with_dask.py b/tests/test_distributed/test_with_dask/test_with_dask.py index 22f7b88c2b49..bb2cbbd8c3f5 100644 --- a/tests/test_distributed/test_with_dask/test_with_dask.py +++ b/tests/test_distributed/test_with_dask/test_with_dask.py @@ -359,7 +359,7 @@ def check_model_output(model: xgb.dask.Booster) -> None: def test_categorical(client: "Client") -> None: X, y = make_categorical(client, 10000, 30, 13) - X_onehot, _ = make_categorical(client, 10000, 30, 13, True) + X_onehot, _ = make_categorical(client, 10000, 30, 13, onehot=True) run_categorical(client, "approx", "cpu", X, X_onehot, y) run_categorical(client, "hist", "cpu", X, X_onehot, y) @@ -1335,7 +1335,7 @@ def test_dmatrix_binary(self, client: "Client") -> None: def save_dmatrix(rabit_args: Dict[str, Union[int, str]], tmpdir: str) -> None: with xgb.dask.CommunicatorContext(**rabit_args): rank = xgb.collective.get_rank() - X, y = tm.make_categorical(100, 4, 4, False) + X, y = tm.make_categorical(100, 4, 4, onehot=False) Xy = xgb.DMatrix(X, y, enable_categorical=True) path = os.path.join(tmpdir, f"{rank}.bin") Xy.save_binary(path) @@ -1665,7 +1665,12 @@ def test_feature_weights(self, client: "Client") -> None: fw = da.from_array(fw) parser = os.path.join(tm.demo_dir(__file__), "json-model", "json_parser.py") poly_increasing = get_feature_weights( - X, y, fw, parser, "approx", model=xgb.dask.DaskXGBRegressor + X=X, + y=y, + fw=fw, + parser_path=parser, + tree_method="approx", + model=xgb.dask.DaskXGBRegressor, ) fw = np.ones(shape=(kCols,)) @@ -1673,7 +1678,12 @@ def test_feature_weights(self, client: "Client") -> None: fw[i] *= float(kCols - i) fw = da.from_array(fw) poly_decreasing = get_feature_weights( - X, y, fw, parser, "approx", model=xgb.dask.DaskXGBRegressor + X=X, + y=y, + fw=fw, + parser_path=parser, + tree_method="approx", + model=xgb.dask.DaskXGBRegressor, ) # Approxmated test, this is dependent on the implementation of random diff --git a/tests/test_distributed/test_with_spark/test_data.py b/tests/test_distributed/test_with_spark/test_data.py index 7f8f1a13ec05..3f88f47b7445 100644 --- a/tests/test_distributed/test_with_spark/test_data.py +++ b/tests/test_distributed/test_with_spark/test_data.py @@ -67,8 +67,8 @@ def run_dmatrix_ctor(is_feature_cols: bool, is_qdm: bool, on_gpu: bool) -> None: cols = [f"feat-{i}" for i in range(n_features)] feature_cols = cols if is_feature_cols else None train_Xy, valid_Xy = create_dmatrix_from_partitions( - iter(dfs), - feature_cols, + iterator=iter(dfs), + feature_cols=feature_cols, dev_ordinal=device_id, use_qdm=is_qdm, kwargs=kwargs,