Skip to content

Recommender

Next-best-product recommendation built from calibrated one-vs-rest binary sub-models assembled into a comparable score matrix over the shared ranking surface. See the recommendation guide.

In short

  • Recommender(cfg).fit(df) trains the sub-models and stores the outcome on result_.
  • Configure it with parleml_ml4.config.recommendation.RecoConfig (entity, product and label columns, grain, negatives, gate).
  • to_pipeline() returns the FittedRecoPipeline you serve; route_cells names the sub-model behind each (entity, product) cell as a CellRoute.
  • Pass outputs_dir= to persist the pipeline under <outputs_dir>/deploy/recommender/.

Recommender

Recommender(
    config: Optional[RecoConfig] = None,
    *,
    trainer: Optional[SubmodelTrainer] = None,
    outputs_dir: Optional[str] = None,
    setup_file_logger: bool = True
)

One-vs-Rest recommendation orchestrator.

Parameters

config: Task configuration. Defaults to RecoConfig(). trainer: Per-sub-model trainer (the seam to AutoSupervised). Defaults to :class:~parleml_ml4.recommendation.trainer.AutoSupervisedTrainer with the configured preset / overrides / calibration. outputs_dir: When set, opt into the events / cancel / deploy discipline (mirrors :class:Forecaster): fit writes events.ndjson / manifest.json and persists a :class:FittedRecoPipeline under <outputs_dir>/deploy/recommender/.

fit

fit(X: RecoInput) -> 'Recommender'

Fit the OvR ensemble + ranking-evaluation surface.

to_pipeline

to_pipeline(
    *, metadata: Optional[dict] = None
) -> "FittedRecoPipeline"

Wrap the fitted recommender into a :class:FittedRecoPipeline.

The fitted pipeline

Recommender.to_pipeline() returns the deployable artefact: it scores, ranks, and names the sub-model behind every (entity, product) cell (route_cells).

FittedRecoPipeline

FittedRecoPipeline(
    *,
    ensemble: RecoEnsemble,
    subcase_policy: SubcasePolicy,
    config: RecoConfig,
    result: RecoResult,
    holdout: Optional[RecoHoldout] = None,
    metadata: Optional[dict] = None
)

Self-contained, persistable One-vs-Rest recommendation artefact.

See docs/recommendation_ovr_plan.md §6.7.

config_feature_cols property

config_feature_cols: list[str]

Feature columns the sub-models expect (recorded on the ensemble meta).

routing_states

routing_states(X: DataFrame) -> dict[str, ndarray]

Per-class routing states for the entity frame X.

Raises when the ensemble was trained with an explicit subcase_col and holds state-specific sub-models: that state cannot be recovered from an entity-level frame, and scoring without it silently routes every cell to one arbitrary expert per class. unified_only ensembles need no states and pass through.

score_matrix

score_matrix(X: DataFrame) -> DataFrame

Calibrated (len(X), n_classes) matrix (no objective transform).

X is one row per entity to score; it must carry the feature columns and — when subcasing is enabled — the holdings column for routing.

route_cells

route_cells(X: DataFrame) -> dict[str, CellRoute]

Which sub-model scores each (row, product) cell of X, and the holding.

The routing :meth:score_matrix applies, exposed per product so a consumer that explains a cell (per-recommendation reasons) explains the sub-model that actually scored it. holding reads the same holdings-derived state as held / previously_held / not_held; it is None when the run has no holdings column (or routes by an explicit subcase_col, whose states are opaque), since then nothing says whether the entity holds the product.

recommend

recommend(
    X: DataFrame,
    *,
    n: Optional[int] = None,
    objective: Optional[RankingObjective] = None,
    shrinkage: Optional[bool] = None,
    rank_percentile: bool = False,
    popularity_discount: Optional[float] = None,
    value_weights: Optional[Mapping[str, float]] = None,
    value_alpha: float = 1.0
) -> dict[str, Any]

Return the calibrated matrix + top-N class names per entity.

objective defaults to the configured ranking_objective; the calibrated probabilities stay available regardless of the sort key.

Two optional, post-training sort-key transforms (both off by default, so the default ranking applies neither):

  • shrinkage — apply Empirical-Bayes shrinkage toward each class's base rate (denoise small-sample classes). None uses the configured shrinkage_strength (also off unless set); True forces it on with a sensible default; False forces it off.
  • rank_percentile — rank within each class's own score distribution before sorting (scale/base-rate-invariant; favours rare classes).

popularity_discount (α) overrides the configured discount when set, so a caller can preview an arbitrary point on the accuracy↔coverage knob without re-fitting; None falls back to config.popularity_discount.

value_weights (per-product business/margin importance) tilts the ranking toward high-value products — sort_key = score · weight ** value_alpha — applied after the relevance/objective transform. Products absent from the map default to weight 1.0 (value-neutral), so it is naturally the either/or counterpart to the popularity discount: leave one neutral to use the other. Off by default.

manifest

manifest() -> dict

Human-readable manifest (per-class routing + per-sub-model meta).

CellRoute dataclass

CellRoute(
    submodel_keys: ndarray, holding: Optional[ndarray]
)

How one product's cells of an entity frame are scored (see route_cells).

Next: Recommendation guide · LTRRanker