Base search cross validation: private API
PortfolioOptimisers.AbstractSearchCrossValidationEstimator — Type
abstract type AbstractSearchCrossValidationEstimator <: AbstractEstimatorAbstract supertype for all search-based cross-validation estimators.
Subtypes implement hyperparameter search strategies (e.g. grid search, randomised search) that use cross-validation to select the best estimator configuration.
Related
PortfolioOptimisers.CrossValSearchScorer — Type
const CrossValSearchScorer = Union{<:CrossValidationSearchScorer, <:Function}Union type for search cross-validation scoring strategies. Accepts either a subtype of CrossValidationSearchScorer or a plain function that accepts a matrix and returns an integer.
PortfolioOptimisers.AbstractSearchCrossValidationAlgorithm — Type
abstract type AbstractSearchCrossValidationAlgorithm <: AbstractAlgorithmAbstract supertype for all search-based cross-validation algorithm types.
Subtypes define the strategy used to select the best hyperparameter combination from the search results (e.g. selecting by highest mean score).
Related
PortfolioOptimisers.finite_candidate_index — Function
finite_candidate_index(
scorer::Union{Function, CrossValidationSearchScorer},
test_scores::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}
) -> Any
Choose the winning candidate of a search, and never let a failed one win.
A candidate that did not finish every fold carries a non-finite entry in its column of the score matrix, and argmax over [0.80, NaN, 0.50] returns the position of the NaN. So the scorer is handed the columns whose every entry is finite, and the index it returns — a position in the matrix it received — is mapped back to the grid through the list of those columns.
The scorer therefore never sees a failed candidate, and it may compute anything on the matrix it receives: a mean, a spread, a rank. A -Inf substitution would be safe only for a scorer that reads order alone, because a column holding -Inf gives NaN for a spread and the NaN wins again.
The raw matrix stays on the result, so its columns line up with the grid and a reader sees which fold failed.
Algorithm
- Mark the columns of
test_scoreswhose every entry is finite. - Throw an
IsNonFiniteErrorwhen no column is finite. - Call
scoreron the view oftest_scoresat the finite columns. - Return the finite column the index the scorer gave names.
Arguments
scorer: The search scorer (CrossValSearchScorer).test_scores: Thefolds × candidates, orpaths × candidates, score matrix.
Validation
- At least one candidate must have finished every fold.
Returns
opt_idx::Integer: The position of the winning candidate in the parameter grid.
Related
PortfolioOptimisers.assert_search_entry — Function
assert_search_entry(est, cv)Refuse an estimator that is not the configuration alone at the door of a search, once, before any candidate is built.
A search scores every candidate through the one fold loop, and a lens is applied before that loop's warm-up, so a cold estimator seeds one state per candidate and nothing is shared or reset. A warm one is refused by name here rather than inside the candidate loop, where the workers of gscv.ex would raise it up to once per candidate. Under every Fold Fit the walk is online_entry_state, because a search tunes the configuration alone whatever the scheme does with it; under an OnlineStep it is the whole assert_online_entry, so a schedule on a stateful field is refused at the door too.
Arguments
est: The estimator the search tunes.cv: The scheme the search scores over.
Validation
- No
cachein the tree ofestholds a state. AnArgumentErrornaming the field is thrown otherwise. - Under an
OnlineStep, everythingassert_online_entryrefuses.
Related
PortfolioOptimisers.pin_draw — Function
pin_draw(cv::MultipleRandomised)
pin_draw(cv)Fix the folds a search scores every candidate over.
A search splits its data once and scores every candidate against the same folds, so a scheme whose split draws from a random stream must draw the same folds for every candidate. A MultipleRandomised with no seed draws from its rng afresh at every split, and the fold loop splits once per candidate, so this draws one seed from that rng and returns the scheme with it set: every candidate's split then resolves the same stream, and so does the search's own split for the row layout. A seeded scheme, and every other scheme, is returned as it is, because its split is already a function of the data alone.
Arguments
cv: The search's scheme.
Returns
cv: The scheme, with aseedset when itssplitwould otherwise draw afresh.
Related
PortfolioOptimisers.score_rows — Function
score_rows(cvr::CrossValidationResult)
score_rows(cvr::MultipleRandomisedResult)The rows of a search's score matrix that a candidate's predictions fill, in the order the fold loop returns them.
The score matrix is indexed by split: row j is the j-th fold the scheme enumerates, and a reader lines the rows up with split's enumeration. A contiguous scheme returns one MultiPeriodPredictionResult whose predictions are in that order, so its rows are every row in order. A MultipleRandomised returns one MultiPeriodPredictionResult per path, each sorted by the start of its test window through sort_predictions!, so its rows are one vector per path: the split rows of that path, in the order the path's predictions come back. write_candidate_scores! zips a candidate's predictions against these rows, so the matrix keeps split's order under either shape.
Arguments
cvr: The split the search scores over.
Returns
rows: The row indices, one range for a contiguous scheme, or one vector of indices per path for a multiple-randomised one.
Related
PortfolioOptimisers.write_candidate_scores! — Function
write_candidate_scores!(test_scores::MatNum, train_scores::Option{<:MatNum}, i::Integer,
predictions::MultiPeriodPredictionResult, rows, r, sgn, kwargs)
write_candidate_scores!(test_scores::MatNum, train_scores::Option{<:MatNum}, i::Integer,
predictions::PopulationPredictionResult, rows, r, sgn, kwargs)Write the per-fold scores of candidate i into column i of a search's score matrices.
The candidate's predictions are what fit_and_predict returned over the search's scheme, one per fold, and rows is score_rows of that scheme's split, so prediction and row are zipped and the column reads in split's order. A population is one series per path, and each path is written against its own rows. Each fold's test score is expected_risk of the fold's prediction, and its train score, written only when train_scores is a matrix, is the risk of the fold's fitted result over its own sample. Both are multiplied by sgn, 1 when bigger_is_better holds for r and -1 otherwise, so a higher score is always better whatever measure r is, which is the orientation a CrossValidationSearchScorer relies on. A fold that failed scores NaN, and finite_candidate_index keeps that column from the scorer.
Arguments
test_scores: Thefolds × candidatestest score matrix.train_scores: The train score matrix of the same shape, ornothingwhen the search records none.i: The candidate's column.predictions: The candidate's predictions over the scheme.rows: The rows the predictions fill, fromscore_rows.r: The risk measure the search scores with.sgn: The sign that orientsrso that higher is better.kwargs: The keyword arguments forwarded toexpected_risk.
Related
PortfolioOptimisers.parse_lens — Function
parse_lens(key::AbstractString)Parse a hyperparameter key string into an Accessors.jl lens.
Converts a dotted string path (e.g., "opt.pe.ce") into a composable lens for getting and setting nested fields of an estimator object.
Arguments
key: Dotted field path string.
Validation
- String keys longer than
EQUATION_LIMITS[].max_lengthare rejected beforeMeta.parse. - Keys deeper than
EQUATION_LIMITS[].max_depthare rejected before the lens-building walk. A string key is measured afterMeta.parse, so one depth bound holds for every shape ofkey.
Returns
- Composed Accessors.jl lens.
Related
PortfolioOptimisers.assert_search_grid_cap — Function
assert_search_grid_cap(total::Integer, detail::AbstractString)
assert_search_grid_cap(factors::AbstractVector{<:Pair})
assert_search_grid_cap(estval::AbstractVector{<:Pair{<:Any, <:AbstractVector}})
assert_search_grid_cap(estval::AbstractDict{<:Any, <:AbstractVector})Assert the total number of search-grid candidates does not exceed the active max_search_grid ceiling.
The grid is an Iterators.product materialised by collect, so k tuned parameters of N values each cost N^k candidates and N^k full cross-validated fits. A per-parameter check never sees that product — the same reasoning that gave the frontier sweep assert_frontier_sweep_cap — so the cap is asserted where the grid is formed, before the collect.
Concatenated parameter sets are a sum of products, not a product: each set is capped as it is built, and the concatenated total is capped again on the way out.
Arguments
total: Candidate count already computed (aBigInton the product path, sincekparameters at the ceiling overflow anInt64before the check reads it).detail: Phrase naming howtotalwas made, interpolated into the message.factors:key => value-countpairs, one per tuned parameter.estval: The parameter grid itself, from which the factors are derived.
Returns
nothing.
Throws
DomainErrorif the count exceedsRESOURCE_LIMITS[].max_search_grid. The message names the count, the factors that made it, and the knob that raises the ceiling.
Related
PortfolioOptimisers._expr_to_lens — Function
_expr_to_lens(ex::Symbol)Convert a bare symbol into a PropertyLens for field access.
Base case for the lens-building recursion: a bare symbol maps directly to an Accessors.PropertyLens.
Arguments
ex::Symbol: A field name symbol.
Returns
Accessors.PropertyLensfor the symbol.
Related
PortfolioOptimisers._eval_index — Function
_eval_index(x)Evaluate a literal index node in the AST without runtime eval.
Converts integer, symbol, or vector expression AST nodes to concrete index values for use in Accessors.IndexLens.
Arguments
x::Integer: An integer index.x::Symbol: A symbolic index.ex::Expr: A vector expression (:vecthead).
Returns
- The evaluated index value.
Related
PortfolioOptimisers.expr_to_lens_chain — Function
expr_to_lens_chain(ex)Convert a Julia expression to a chain of lens accessors.
Internal helper for parsing hyperparameter key strings into composable Accessors.jl lenses.
Arguments
ex: Julia expression representing a field access chain.
Returns
- Composed lens.
Related
PortfolioOptimisers.pipeline_asset_view — Function
pipeline_asset_view(data::AbstractReturnsResult, cols)
pipeline_asset_view(data::AbstractPricesResult, cols)Return the asset-subset view of price- or returns-level data for a MultipleRandomised resampling path — all observations, only the columns cols.
The two levels index assets through different port_opt_view arities: returns take the two-argument asset form port_opt_view(rd, cols), prices the observation-then-asset form port_opt_view(pr, :, cols). This wrapper hides that asymmetry so pipeline_path_fit_and_predict stays level-agnostic.
Related