Pool keeps feature metadata with the data and avoids repeated preprocessing, which matters for eval sets and large data.
A `Pool` bundles everything CatBoost needs to know about a dataset:
Pool(data=X, label=y, cat_features=[...], text_features=[...],
weight=w, group_id=g, baseline=b)data: DataFrame, NumPy array or a path to a file in CatBoost's TSV format (with a column description file)label: the target (omit it for prediction-only pools)cat_featuresandtext_features: column names or indicesweight: per-row weights;group_id: query ids for rankingbaseline: starting predictions to boost from
Why use it instead of plain arrays?
- Feature metadata travels with the data, so the training set and eval set can't disagree about which columns are categorical.
- CatBoost converts the data to its internal format once. Re-using a Pool across several
fitcalls or for evaluation avoids repeating that work. Pool.quantize()precomputes feature borders for large datasets, and file-based pools let the C++ core load data without going through pandas.
model.fit(train_pool, eval_set=valid_pool) and model.predict(test_pool) accept pools directly. pool.num_row(), pool.num_col() and pool.get_cat_feature_indices() inspect them. Pool.slice(indices) takes a subset of rows.
Example
import numpy as np
import pandas as pd
from catboost import CatBoostRegressor, Pool
rng = np.random.default_rng(0)
df = pd.DataFrame({"size": rng.uniform(30, 150, 400),
"district": rng.choice(["north", "south", "center"], 400)})
price = df["size"] * 3 + df["district"].map({"north": 50, "south": 0, "center": 120})
w = np.where(df["district"] == "center", 2.0, 1.0) # weight center rows more
train = Pool(df[:300], label=price[:300], cat_features=["district"], weight=w[:300])
valid = Pool(df[300:], label=price[300:], cat_features=["district"])
print(train.num_row(), train.num_col(), train.get_cat_feature_indices()) # 300 2 [1]
model = CatBoostRegressor(iterations=300, verbose=0, random_seed=0,
allow_writing_files=False)
model.fit(train, eval_set=valid)
test = Pool(pd.DataFrame({"size": [100.0], "district": ["center"]}), cat_features=[1])
print(model.predict(test).round()) # about [420.]Remember
- Pool holds data, label, cat/text features, weights, group ids and baseline
- Use pools so training and eval data share the same feature metadata
- fit, eval_set and predict all accept Pools
- Data is converted once, which saves time on large datasets
Watch out for
- Declaring cat_features on the training data but passing a plain DataFrame without them as eval_set in older code paths; use Pools for both.