code: def check_categorical_missing(
      rows: int, cols: int, cats: int, device: str, tree_method: str
  ) -> None:
      """Check categorical data with missing values."""
      parameters: Dict[str, Any] = {
          "tree_method": tree_method,
          "device": device,
      }
      cat, label = tm.make_categorical(
          rows,
          n_features=cols,
          n_categories=cats,
          onehot=False,
          sparsity=0.5,
      )
      Xy = xgb.DMatrix(cat, label, enable_categorical=True)
  
      def run(max_cat_to_onehot: int) -> None:
          # Test with onehot splits
          parameters["max_cat_to_onehot"] = max_cat_to_onehot
  
          evals_result: Dict[str, Dict] = {}
          booster = xgb.train(
              parameters,
              Xy,
              num_boost_round=16,
              evals=[(Xy, "Train")],
              evals_result=evals_result,
          )
          assert tm.non_increasing(evals_result["Train"]["rmse"])
          y_predt = booster.predict(Xy)
  
          rmse = tm.root_mean_square(label, y_predt)
          np.testing.assert_allclose(
              rmse, evals_result["Train"]["rmse"][-1], rtol=2e-5
          )
  
      # Test with OHE split
      run(USE_ONEHOT)
  
      # Test with partition-based split
      run(USE_PART)
  
file_path: xgboost/python-package/xgboost/testing/updater.py
imports: import json
  from functools import partial, update_wrapper
  from typing import Any, Dict, List
  import numpy
  import xgboost
  import xgboost.testing
label_desc: Use image node_id 8 for calling a global function with example usage: check_categorical_missing(rows, cols, cats, device, tree_method) without return types