Repository: modin-project/modin

Issue:
`evals` parameter of Modin xgb.train not correctly processed on the small data shapes
`modin.experimental.xgboost.train` throws exception when the number of partitions in `DMatrix` of `evals` parameter is less than the number of created actors.

Code to reproduce:
```python
from modin.experimental.sklearn.model_selection.train_test_split import train_test_split
import modin.experimental.xgboost as xgb
import modin.pandas as pd

from sklearn.datasets import load_diabetes

import multiprocessing as mp

X_df = pd.DataFrame(load_diabetes().data)
y_df = pd.DataFrame(load_diabetes().target)
X_train, X_test = train_test_split(X_df)
y_train, y_test = train_test_split(y_df)

train_dmatrix_mxgb = xgb.DMatrix(X_train, label=y_train)
test_dmatrix_mxgb = xgb.DMatrix(X_test, label=y_test)

evals_result_mxgb = {}
modin_bst = xgb.train(
    {"eta": 0.01,},
    train_dmatrix_mxgb,
    10,
    evals_result=evals_result_mxgb,
    evals=[(train_dmatrix_mxgb, "train"), (test_dmatrix_mxgb, "test")],
    num_actors=mp.cpu_count(),
)
```
Output:
```bash
Traceback (most recent call last):
  File "test.py", line 18, in <module>
    modin_bst = xgb.train(
  File "/localdisk/aprutsko/modin/modin/experimental/xgboost/xgboost.py", line 191, in train
    result = _train(dtrain, num_actors, params, *args, evals=evals, **kwargs)
  File "/localdisk/aprutsko/modin/modin/experimental/xgboost/xgboost_ray.py", line 637, in _train
    _split_data_across_actors(
  File "/localdisk/aprutsko/modin/modin/experimental/xgboost/xgboost_ray.py", line 384, in _split_data_across_actors
    X_parts_by_actors = _assign_row_partitions_to_actors(
  File "/localdisk/aprutsko/modin/modin/experimental/xgboost/xgboost_ray.py", line 539, in _assign_row_partitions_to_actors
    parts, order = zip(*pairs_part_pos)
ValueError: not enough values to unpack (expected 2, got 0)
```

When `num_actors=None`  than we just see a hang.



Discussion:

Resolving patch:
diff --git a/modin/experimental/xgboost/xgboost_ray.py b/modin/experimental/xgboost/xgboost_ray.py
--- a/modin/experimental/xgboost/xgboost_ray.py
+++ b/modin/experimental/xgboost/xgboost_ray.py
@@ -23,6 +23,7 @@
 from typing import Dict, List
 import math
 from collections import defaultdict
+import warnings
 
 import numpy as np
 import xgboost as xgb
@@ -498,6 +499,19 @@ def _train(
     if num_actors > len(X_row_parts):
         num_actors = len(X_row_parts)
 
+    if evals:
+        min_num_parts = num_actors
+        for (eval_X, _), eval_method in evals:
+            if len(eval_X) < min_num_parts:
+                min_num_parts = len(eval_X)
+                method_name = eval_method
+
+        if num_actors != min_num_parts:
+            num_actors = min_num_parts
+            warnings.warn(
+                f"`num_actors` is set to {num_actors}, because `evals` data with name `{method_name}` has only {num_actors} partition(s)."
+            )
+
     actors = create_actors(num_actors)
 
     add_as_eval_method = None


Test patch:
diff --git a/modin/experimental/xgboost/test/test_xgboost.py b/modin/experimental/xgboost/test/test_xgboost.py
--- a/modin/experimental/xgboost/test/test_xgboost.py
+++ b/modin/experimental/xgboost/test/test_xgboost.py
@@ -218,9 +218,9 @@ def test_xgb_with_multiclass_classification_datasets(data, num_actors, modin_typ
     "num_actors",
     [
         1,
-        pytest.param(num_cpus, marks=pytest.mark.skip),
-        pytest.param(None, marks=pytest.mark.skip),
-        pytest.param(modin.config.NPartitions.get() + 1, marks=pytest.mark.skip),
+        num_cpus,
+        None,
+        modin.config.NPartitions.get() + 1,
     ],
 )
 @pytest.mark.parametrize(