Surrogate¶
Cheap regression surrogates fit over a ResultsTable
for predicting observables at untested configurations.
Install via the optional extra:
trade_study.fit_surrogate(results, factors, *, method='gp', seed=0, n_estimators=200, cv_folds=5, warn_below_r2=0.0, cv_group_by=None, cv_groups=None)
¶
Fit a per-observable surrogate over a :class:ResultsTable.
Rows whose score column contains NaN are dropped on a
per-observable basis (so a partially-evaluated trial still
contributes to the observables it does have).
After fitting each observable's model on all its available rows,
also computes a held-out cross-validated R^2/RMSE so callers
can tell a well-fit surrogate from one that's effectively guessing
in a sparse or noisy region of the design space -- neither backend
reports this on its own (RF's cheap OOB score isn't available for
GP, so CV is used uniformly for both, at the cost of cv_folds
extra fits per observable).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
results
|
ResultsTable
|
A :class: |
required |
factors
|
list[Factor]
|
Factor definitions used to encode |
required |
method
|
str
|
|
'gp'
|
seed
|
int
|
Random seed forwarded to the backend estimators. |
0
|
n_estimators
|
int
|
Number of trees for the |
200
|
cv_folds
|
int
|
Number of cross-validation folds used to compute
|
5
|
warn_below_r2
|
float | None
|
If not |
0.0
|
cv_group_by
|
str | Sequence[str] | None
|
|
None
|
cv_groups
|
Sequence[object] | NDArray[Any] | None
|
Explicit group labels aligned with all results rows, mutually exclusive with cv_group_by. Useful for shared dataset/replicate IDs supplied from metadata. Labels are finite numbers, strings, bytes or tuples thereof; missing labels and other objects are refused. One partition tests one caller-declared generalization target. |
None
|
Returns:
| Type | Description |
|---|---|
SurrogateModel
|
A fitted :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/trade_study/surrogate.py
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | |
Validation and support¶
fit_surrogate(..., cv_group_by="design") keeps identical factor configurations
in one validation fold, preventing replicates of a design from appearing in
both training and validation. Pass a sequence such as cv_group_by=["noise"]
to hold out whole regimes. cv_r2 and cv_rmse then describe held-out groups;
row_cv_r2 and row_cv_rmse retain shuffled row validation for comparison.
With both group options unset, the existing row validation behavior is retained.
Grouping is explicit: different design-point ids with identical factor values
belong to the same design group. Fewer than two groups produce nan metrics;
constant targets have undefined R². Non-finite scores are excluded separately
for each observable. validation_groups exposes row-aligned group ids.
Use cv_groups=[meta["dataset_id"] for meta in results.metadata] for an explicit
shared-dataset/replicate partition across configurations. It is mutually exclusive
with cv_group_by and must align with all original rows. Finite scalar/tuple
labels are validated without splitting equal numeric identities; missing labels
are refused. cv_group_source and cv_group_labels preserve the source and
external labels. One partition does not automatically block crossed dependencies.
See the complete conditional workflow for the
distinction between held-out designs, regimes and datasets.
model.support(configs) reports continuous factors outside the observed
training range and categorical/discrete levels absent from finite training rows
for each observable. Predictions warn by default and still extrapolate without
clipping. Use warn_support=False to disable these warnings explicitly.
Levels outside the factor's declared domain remain invalid. Bounds use raw
factor units, including for log-scaled factors. Marginal ranges do not establish
joint support, adequate sampling density, or calibrated prediction uncertainty.
trade_study.SurrogateModel(method, encoder, observable_names, models, cv_r2=dict(), cv_rmse=dict(), row_cv_r2=dict(), row_cv_rmse=dict(), cv_group_by=None, validation_groups=list(), support_ranges=dict(), support_levels=dict(), cv_group_source='rows', cv_group_labels=None)
dataclass
¶
Fitted surrogate over a :class:ResultsTable.
Use :func:fit_surrogate to construct one. Per-observable backend
estimators are stored in models; encoding is shared across them.
Attributes:
| Name | Type | Description |
|---|---|---|
method |
str
|
|
encoder |
_FactorEncoder
|
Factor encoder used at fit time. |
observable_names |
list[str]
|
Column names of the predicted observables. |
models |
list[Any]
|
One fitted scikit-learn estimator per observable. |
cv_r2 |
dict[str, float]
|
Per-observable held-out cross-validated R^2. Missing
for an observable if too few rows were available to run CV
(fewer than 2 folds); |
cv_rmse |
dict[str, float]
|
Per-observable held-out cross-validated RMSE, companion
to |
row_cv_r2 |
dict[str, float]
|
Shuffled row-validation R², even when grouping is selected. |
row_cv_rmse |
dict[str, float]
|
Shuffled row-validation RMSE in observable units. |
cv_group_by |
tuple[str, ...] | None
|
Configuration grouping names, or None for rows/external groups. |
cv_group_source |
str
|
"rows", "configuration" or explicit "external" labels. |
cv_group_labels |
tuple[Hashable, ...] | None
|
Validated external labels aligned with results rows, or None. Equal finite numeric labels share one group. |
validation_groups |
list[int]
|
Group ids aligned with the original results rows. |
support_ranges |
dict[str, dict[str, tuple[float, float]]]
|
Observed continuous bounds per fitted observable. |
support_levels |
dict[str, dict[str, list[Any]]]
|
Observed levels per fitted observable. |
support(configs)
¶
Inspect observed support without predicting or emitting warnings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
configs
|
Sequence[dict[str, Any]]
|
Factor configurations to inspect. |
required |
Returns:
| Type | Description |
|---|---|
list[PredictionSupport]
|
One diagnostic per configuration and fitted observable. Support |
list[PredictionSupport]
|
uses finite training rows for that observable, in raw factor units. |
Source code in src/trade_study/surrogate.py
predict(config, *, warn_support=True)
¶
Predict observables for a single config.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Factor-keyed config dict. |
required |
warn_support
|
bool
|
Warn on values outside observed training support. |
True
|
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
Mapping from observable name to predicted scalar. |
Source code in src/trade_study/surrogate.py
predict_batch(configs, *, warn_support=True)
¶
Predict observables for a batch of configs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
configs
|
Sequence[dict[str, Any]]
|
Sequence of factor-keyed config dicts. |
required |
warn_support
|
bool
|
Warn on values outside observed training support. |
True
|
Returns:
| Type | Description |
|---|---|
dict[str, NDArray[float64]]
|
Mapping from observable name to a length- |
dict[str, NDArray[float64]]
|
array of predictions. |
Source code in src/trade_study/surrogate.py
spread_batch(configs, *, warn_support=True)
¶
Predictive spread per observable for a batch of configs.
For method="gp" this is the predictive standard deviation; for
method="rf" it is the standard deviation of the individual trees'
predictions, a relative (not calibrated) measure of disagreement.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
configs
|
Sequence[dict[str, Any]]
|
Sequence of factor-keyed config dicts. |
required |
warn_support
|
bool
|
Warn on values outside observed training support. |
True
|
Returns:
| Type | Description |
|---|---|
dict[str, NDArray[float64]]
|
Mapping from observable name to a length- |
Source code in src/trade_study/surrogate.py
uncertainty(config, *, warn_support=True)
¶
Predictive standard deviation per observable (GP only).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Factor-keyed config dict. |
required |
warn_support
|
bool
|
Warn on values outside observed training support. |
True
|
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
Mapping from observable name to predictive standard deviation. |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If the backend does not expose calibrated
uncertainties (currently anything other than |
Source code in src/trade_study/surrogate.py
trade_study.PredictionSupport(config_index, observable, outside_ranges, unseen_levels)
dataclass
¶
Marginal training-support diagnostics for one query and observable.
These checks flag extrapolation; they do not establish joint support or provide a calibrated uncertainty guarantee.
supported
property
¶
Whether every factor lies within its observed marginal support.
Returns:
| Type | Description |
|---|---|
bool
|
True when no range or level check failed. |