openquant.ensemble
Compiled from Rust (crates/pyopenquant). Signatures and types are from the shipped .pyi stubs; descriptions are the functions’ own docstrings, as help() shows them. All Python modules.
Functions
aggregate_classification_probability_mean
aggregate_classification_probability_mean(
per_model_probabilities: Sequence[Sequence[float]],
threshold: float,
) -> tuple[list[float], list[int]]Mean predicted probability per observation, and the label it implies at threshold.
The averaged probability is what bet sizing (AFML Chapter 10) takes as input. Every input probability must lie in [0, 1].
Parameters
per_model_probabilities: list[list[float]]One row per model, one probability of class 1 per observation; every row the same length.
threshold: floatCut-off in
[0, 1]; a label is 1 when the mean probability is>= threshold.
Returns
- tuple[list[float], list[int]]
(probabilities, labels): the mean probability and the 0/1 label per observation.
Raises
- ValueError
If there are no model rows, the first row is empty, the rows differ in length,
thresholdis outside[0, 1]or NaN, or any input probability is outside[0, 1]or NaN.
aggregate_classification_vote
aggregate_classification_vote(
per_model_predictions: Sequence[Sequence[int]],
) -> list[int]Majority vote over binary class predictions (AFML section 6.3.2).
An observation is labelled 1 when at least half of the models vote 1, so a tie goes to 1. The vote discards confidence; aggregate_classification_probability_mean keeps it.
Parameters
per_model_predictions: list[list[int]]One row per model, one 0/1 label per observation; every row the same length.
Returns
- list[int]
The voted 0/1 label per observation.
Raises
- ValueError
If there are no model rows, the first row is empty, the rows differ in length, or a label is not 0 or 1.
aggregate_regression_mean
aggregate_regression_mean(
per_model_predictions: Sequence[Sequence[float]],
) -> list[float]Element-wise mean of the models' predictions: the bagged regression forecast (AFML 6.3).
Parameters
per_model_predictions: list[list[float]]One row per model, one column per observation; every row the same length.
Returns
- list[float]
The mean prediction per observation.
Raises
- ValueError
If there are no model rows, the first row is empty, or the rows differ in length.
average_pairwise_prediction_correlation
average_pairwise_prediction_correlation(
per_model_predictions: Sequence[Sequence[float]],
) -> floatMean Pearson correlation over all pairs of model rows: the rho-bar of AFML section 6.3.1.
Pass the models' errors (residuals) to get the rho-bar that bagging_ensemble_variance expects; on raw predictions of a common target the correlation mostly measures that every model tracks the target. A pair involving a constant row contributes a correlation of 0.
Parameters
per_model_predictions: list[list[float]]One row per model, one column per observation; every row the same length.
Returns
- float
The average of the pairwise correlations.
Raises
- ValueError
If there are fewer than two model rows, the first row has fewer than two entries, or the rows differ in length.
bagging_ensemble_variance
bagging_ensemble_variance(
single_estimator_variance: float,
average_correlation: float,
n_estimators: int,
) -> floatVariance of the average of N estimators, sigma2 * (rho + (1 - rho) / N) (AFML 6.3.1).
As N grows the result falls to the floor sigma2 * rho, which no number of estimators moves: redundant, correlated estimators limit what bagging can achieve.
Parameters
single_estimator_variance: floatCommon variance
sigma2of one estimator's predictions; must be finite and non-negative.average_correlation: floatAverage pairwise correlation
rhobetween estimators, in[-1, 1], e.g. fromaverage_pairwise_prediction_correlation.n_estimators: intNumber of estimators N; must be positive.
Returns
- float
The variance of the ensemble average.
Raises
- ValueError
If
single_estimator_varianceis negative, NaN or infinite,average_correlationis outside[-1, 1]or NaN, orn_estimatorsis 0.
bias_variance_noise
bias_variance_noise(
y_true: Sequence[float],
per_model_predictions: Sequence[Sequence[float]],
y_expected: Sequence[float] | None = None,
) -> tuple[float, float, float | None, float]Bias-variance-noise decomposition of an ensemble's forecasts (AFML section 6.2).
All terms are averaged over observations. variance is the population variance of the models' predictions around their mean, per observation, and mse is the error of the individual models against y_true, averaged over models and observations. Without y_expected, bias_sq = mean((mean_pred - y_true)**2) includes the irreducible noise, noise is None and bias_sq + variance == mse exactly. With y_expected (the noiseless target E[y|x], known in simulation studies), the bias is measured against it and noise = mean((y_true - y_expected)**2), so the three terms add up to mse in expectation.
Parameters
y_true: list[float]Observed targets, one per observation.
per_model_predictions: list[list[float]]One row per model, each as long as
y_true.y_expected: list[float] | None, default NoneNoiseless target E[y|x] per observation, as long as
y_true.
Returns
- tuple[float, float, float | None, float]
(bias_sq, variance, noise, mse);noiseis None unlessy_expectedis given.
Raises
- ValueError
If
y_trueorper_model_predictionsis empty, or a model row ory_expecteddiffers in length fromy_true.
bootstrap_sample_indices
bootstrap_sample_indices(n_samples: int, sample_size: int, seed: int) -> list[int]Draw a uniform bootstrap sample of indices, with replacement (AFML section 6.3).
This is the standard bagging bootstrap; it ignores label overlap (see sequential_bootstrap_sample_indices for the uniqueness-aware alternative). The draw is reproducible for a given seed.
Parameters
n_samples: intSize of the population; indices are drawn from
range(n_samples).sample_size: intNumber of indices to draw.
seed: intSeed of the random generator.
Returns
- list[int]
sample_sizeindices in[0, n_samples), in draw order, possibly repeated.
Raises
- ValueError
If
n_samplesorsample_sizeis 0.
recommend_bagging_vs_boosting
recommend_bagging_vs_boosting(
base_estimator_accuracy: float,
average_prediction_correlation: float,
label_redundancy: float,
single_estimator_variance: float,
n_estimators: int,
) -> AnyExpected bagging variance plus a rule-of-thumb bagging-or-boosting label (AFML 6.6).
The label is "boosting" if base_estimator_accuracy < 0.55, or average_prediction_correlation >= 0.75, or label_redundancy >= 0.70, and "bagging" otherwise. The reasoning follows AFML section 6.6 (bagging reduces variance, boosting reduces bias, and bagging cannot rescue a learner barely better than chance), but the three cut-offs are this library's, not the book's; AFML's own conclusion is that bagging is generally preferable in finance. Treat the label as a prompt to look at the numbers.
Parameters
base_estimator_accuracy: floatAccuracy of a single base estimator, in
[0, 1].average_prediction_correlation: floatAverage pairwise correlation between estimators, in
[-1, 1].label_redundancy: floatLabel redundancy in
[0, 1], e.g. one minus the average uniqueness of the labels.single_estimator_variance: floatVariance of one estimator's predictions; must be non-negative.
n_estimators: intNumber of estimators in the ensemble; must be positive.
Returns
- dict[str, Any]
A dict with keys
recommended(str, "bagging" or "boosting"),expected_bagging_variance(float, frombagging_ensemble_variance) andexpected_variance_reduction(float,single_estimator_varianceminus the expected bagging variance, floored at 0).
Raises
- ValueError
If
base_estimator_accuracyorlabel_redundancyis outside[0, 1]or NaN, or if the core rejects the variance inputs (negativesingle_estimator_variance,average_prediction_correlationoutside[-1, 1], orn_estimators == 0).
sequential_bootstrap_sample_indices
sequential_bootstrap_sample_indices(
ind_mat: Sequence[Sequence[int]],
sample_size: int,
seed: int,
) -> list[int]Draw label indices with the sequential bootstrap (AFML section 4.5.1, Snippets 4.5-4.6).
Labels are drawn one at a time, with replacement, each with probability proportional to its average uniqueness given the draws so far, so overlapping labels are drawn less often than under a uniform bootstrap. The draw is reproducible for a given seed (but differs from bootstrap_sample_indices with the same seed).
Parameters
ind_mat: list[list[int]]Bars x labels indicator matrix (e.g. from
openquant.sampling): one row per bar, one column per label, 1 where the label spans the bar and 0 elsewhere.sample_size: intNumber of labels to draw; must be positive.
seed: intSeed of the random generator.
Returns
- list[int]
sample_sizecolumn (label) indices ofind_mat, in draw order, possibly repeated.
Raises
- ValueError
If
sample_sizeis 0,ind_mathas no rows, its first row is empty, or its rows differ in length.