projectionmodels

Focused actuarial projections of claims, premium, and expenses on supplied exposure. The package is intentionally organized around concrete workflows — most users should not need to construct a calculation graph or define a custom state engine. It depends on actuarialpy for its completion, trend, seasonality, and credibility estimation. Example 7 runs the whole renewal cycle end to end — estimated assumptions, a credibility-blended claim projection, indicated and capped rate actions fed back through RenewalRateActions, expenses on three bases, and the projected loss-ratio path.

The package root contains the workflow objects most actuaries need:

Object

Role

project / base_rates

Build the projection from the canonical Experience

ClaimProjection

Project claim rates and claims by claim type

PremiumProjection

Roll premium forward, including renewal rate actions

RenewalRateActions

Supply effective-dated rate actions

ExpenseProjection

Project per-exposure, fixed, premium-based, and claim-based expenses

ProjectionHorizon

Define monthly, quarterly, or annual projection periods

ProjectionDates

Define entry, exit, renewal, and experience date columns

DateCohort

Split records into existing/new or other date cohorts

Adjustment / Scenario

Run sensitivities and alternative assumptions

ProjectionResults

Summarize without averaging ratios or duplicating exposure

Lower-level modeling objects are available from projectionmodels.advanced, but they are not part of the primary workflow.

Quickstart: premium at renewal

import pandas as pd
import projectionmodels as pm

premium_data = pd.DataFrame({
    "group_id": ["A", "B"],
    "renewal_date": pd.to_datetime(["2027-03-01", "2027-07-01"]),
    "current_premium_rate": [100.0, 100.0],
    "rate_action": [0.10, 0.20],
})

periods = pd.period_range("2027-01", periods=12, freq="M").astype(str)
exposure = pd.DataFrame(
    [{"group_id": g, "projection_period": p, "exposure_units": 1_000.0}
     for g in ("A", "B") for p in periods]
)

results = pm.PremiumProjection(
    premium_data=premium_data,
    projection_keys=["group_id"],
    exposure=exposure,
    exposure_col="exposure_units",
    horizon=pm.ProjectionHorizon("2027-01-01", periods=12),
    recurring_rate_action_col="rate_action",
).project()

Group A remains at $100 through February, increases to $110 at its March renewal, and carries that rate forward; group B increases to $120 in July. For different actions at different renewals, provide an effective-dated RenewalRateActions table instead of a recurring action column.

Claims by claim type

project builds the projection straight from the canonical actuarialpy.Experience: the record grain defaults to the bound dimensions, and the claim-type dimension is inferred as the grain column absent from the exposure frame (pass claim_type= when ambiguous). A wide Experience built with a wide_by= pivot melts itself – the recorded pivot becomes the claim-type dimension, and non-pivot expense columns are announced as excluded. seasonality="estimate" fits factors from the bound history; trend is always a stated selection, never a silent estimate:

from actuarialpy import Experience

experience = Experience(
    hist,
    expense="reported_claims",
    exposure="exposure_units",
    date="incurred_month",
    dimensions=["group_id", "claim_type"],
    valuation_date="2026-12-31",
)

projection = pm.project(
    experience,
    exposure=exposure,
    exposure_col="exposure_units",
    horizon=pm.ProjectionHorizon("2027-01-01", periods=12),
    trend=pm.TrendAssumption.from_values("claim_trend", 0.06),
    # optionally: completion=, seasonality=, credibility=, complement=
)

results = projection.project()
results.to_frame()      # per key × claim type × period detail

Trend, seasonality, completion, and credibility may be supplied directly as assumption tables (TrendAssumption.from_values and friends) or estimated from history (below).

Cost levels and pipeline order

The claim workflow evaluates, in order: complete → deseasonalize → trend the experience rate to the blend basis → credibility blend → trend from the basis to each projection period → reseasonalize → add rate_loads → multiply by exposure. Exposure is whatever unit the book uses — member-months, policy-months, car-years — named with exposure_col.

The complement is used as stated. By default the blend basis is the prospective midpoint of the horizon (complement_basis="prospective"), the level at which manual and book rates are conventionally quoted — so a zero-credibility projection reproduces the complement rather than a trended copy of it. Set complement_basis="experience" if your complement is quoted at experience-period cost level, or pass an explicit as-of date. Because the month arithmetic is exactly additive, results at full credibility are identical under every basis.

rate_loads (for example a pooling charge) are added to the projected rate as stated: flat across periods, after seasonality, outside the blend.

Estimating assumptions with actuarialpy

Estimation is explicit and separate from projection execution. The projectionmodels.integrations.actuarialpy adapters estimate each assumption with the corresponding core primitive (completion_factors, fit_trend, seasonality_factors, limited_fluctuation_z) and return assumption objects that retain indicated values and diagnostics:

from projectionmodels.integrations.actuarialpy import (
    estimate_completion,
    estimate_credibility,
    estimate_seasonality,
    estimate_trend,
)

trend = estimate_trend(
    "claim_trend",
    deseasonalized_history,
    by=["claim_type"],
    date_col="incurred_month",
    value_col="deseasonalized_claims",
    exposure_col="exposure_units",
)

An actuary can replace an indication while preserving the audit trail — the assumption keeps both the estimate and the selection.

Results

ProjectionResults holds the per-period detail and summarizes it: amounts are summed, and rates are recomputed from the summed amounts and exposure:

results.to_frame()                       # full detail
results.summarize(by="calendar_quarter") # weighted rates, summed exposure and amounts

API reference

Focused actuarial claim, premium, and expense projection workflows on supplied exposure.

class Adjustment(target: str, method: str, value: ~typing.Any, name: str | None = None, filters: ~collections.abc.Mapping[str, ~typing.Any] = <factory>, effective_from: ~typing.Any | None = None, effective_to: ~typing.Any | None = None, priority: int = 100)[source]

Bases: object

Modify a named input, assumption, or roll-forward under a scenario.

class Assumption(name: str, values: ~typing.Any, lookup: tuple[str, ...] | list[str] = <factory>, value_col: str | None = None, source: str = 'supplied', indicated_values: ~typing.Any | None = None, diagnostics: ~typing.Any | None = None, metadata: ~collections.abc.Mapping[str, ~typing.Any] = <factory>)[source]

Bases: object

A named assumption resolved by explicit lookup fields.

values may be a scalar, Series, or DataFrame. DataFrame assumptions are joined many-to-one on lookup and must contain value_col.

audit_frame() DataFrame[source]

Return a compact assumption-audit table.

resolve(frame: DataFrame, *, strict: bool = True) Series[source]

Resolve assumption values onto frame in its original row order.

select(selection: Any, *, lookup: str | Iterable[str] | None = None, value_col: str | None = None, note: str | None = None) Assumption[source]

Replace indicated values with an actuarial selection while retaining audit data.

class BookProjection(projections, labels=None)[source]

Bases: object

Roll a set of group projections up into the book: totals, per-group, monthly.

Accepts GroupProjection objects (or their results) and aggregates the expected – renewal-probability-weighted – premium and claims, so a group contributes in proportion to how likely it is to renew. Exposes premium / claims / loss_ratio (book totals), by_group (one row per group with its expected figures and renewal probability), and monthly (expected premium and claims by projection month, summed over the book); the assembled BookResult sits on result. All inputs must share one projection horizon – the monthly frames are summed elementwise.

Parameters:
  • projections (sequence of GroupProjection or GroupProjectionResult) – The in-force renewals and new business to aggregate.

  • labels (sequence of str, optional) – Group labels for by_group (default grp_0, grp_1, …); must match projections in length.

base_rates(exp: Experience, *, grain: str | Iterable[str] | None = None, completion: CompletionAssumption | None = None, seasonality: SeasonalityAssumption | None = None, complement: Assumption | Any | None = None, extra_record_cols: Iterable[str] = (), claims_col: str | None = None) DataFrame[source]

Aggregate prepared experience to one row per projection record.

grain names the record columns (projection keys plus the claim-type dimension) and defaults to the dimensions bound on the Experience. Produces experience_claim_rate, the exposure-weighted experience_midpoint, and – when given – complement_claim_rate: the columns ClaimProjection consumes.

prepare_experience(exp: Experience, *, completion: CompletionAssumption | None = None, seasonality: SeasonalityAssumption | None = None, claims_col: str | None = None) DataFrame[source]

Return experience with completed and deseasonalized claim columns.

Takes the canonical actuarialpy.Experience – the bound expense, date, and exposure roles and the object’s valuation_date fill the column plumbing – and applies the projection assumptions in pipeline order (completion, then seasonality). The working column is carried to projectionmodels_adjusted_claims for base_rates().

project(exp: Experience, *, exposure: DataFrame, horizon: ProjectionHorizon, trend: TrendAssumption, seasonality: SeasonalityAssumption | None = None, credibility: CredibilityAssumption | None = None, completion: CompletionAssumption | None = None, complement: Assumption | Any | None = None, complement_basis: str | Timestamp = 'prospective', rate_loads: Any = (), grain: str | Iterable[str] | None = None, claim_type: str | None = None, extra_record_cols: Iterable[str] = (), claims_col: str | None = None, exposure_col: str | None = None, exposure_period_col: str = 'projection_period', dates: ProjectionDates | None = None) ClaimProjection[source]

Build a ClaimProjection from the canonical Experience.

The single projection entrypoint: takes an actuarialpy.Experience plus only the concepts this package owns – the assumptions, the horizon, and the prospective exposure. Named parameters are the pipeline phases; ordering (complete, deseasonalize, aggregate, trend / blend) is fixed and never inferred from a list.

grain defaults to the Experience’s bound dimensions. Of the grain columns, the ones present in exposure are the projection keys (rates join to exposure on them); the one absent is the claim-type dimension (rates vary by it, exposure does not). Pass claim_type= when the split is ambiguous.

class ClaimProjection(base_rates: ~pandas.DataFrame, projection_keys: tuple[str, ...] | list[str], claim_type_col: str, exposure: ~pandas.DataFrame, horizon: ~projectionmodels.horizon.ProjectionHorizon, trend: ~projectionmodels.assumptions.TrendAssumption, seasonality: ~projectionmodels.assumptions.SeasonalityAssumption | None = None, credibility: ~projectionmodels.assumptions.CredibilityAssumption | None = None, complement_basis: str | ~pandas.Timestamp = 'prospective', rate_loads: ~typing.Any = (), exposure_col: str = 'exposure', exposure_period_col: str = 'projection_period', dates: ~projectionmodels.data.ProjectionDates | None = None, additional_assumptions: tuple[~projectionmodels.assumptions.Assumption, ...] | list[~projectionmodels.assumptions.Assumption] = <factory>)[source]

Bases: object

Project credibility-blended claim rates onto supplied exposure.

Exposure is whatever unit the book uses — member-months, policy months, earned car-years — supplied by projection key and period and named with exposure_col.

Pipeline, in order:

  1. experience_claim_rate is trended from each record’s experience_midpoint to the blend basis (trended_experience_rate).

  2. The trended experience is credibility blended with complement_claim_rate as stated (credible_claim_rate).

  3. The blended rate is trended from the blend basis to each period’s midpoint (trended_claim_rate).

  4. Seasonality redistributes within the year and rate_loads are added, flat and outside the blend (projected_claim_rate).

  5. Rates are multiplied by exposure (projected_claims).

Cost levels — complement_basis declares the level at which the complement is quoted:

  • "prospective" (default): the horizon’s mean period midpoint, the conventional level for manual and book rates. Zero credibility therefore reproduces the complement as stated.

  • "experience": the record’s experience midpoint, so the complement is trended alongside experience (the pre-0.5.0 behaviour).

  • an explicit date: any other as-of level.

Because the calendar month arithmetic is exactly additive, projections at full credibility are identical under every basis.

rate_loads (for example a pooling charge) are Assumptions or scalars quoted at prospective level; they are added to the projected rate as stated, per period, after seasonality, and are not credibility weighted.

class CompletionAssumption(name: str, values: ~typing.Any, lookup: tuple[str, ...] | list[str] = <factory>, value_col: str | None = None, source: str = 'supplied', indicated_values: ~typing.Any | None = None, diagnostics: ~typing.Any | None = None, metadata: ~collections.abc.Mapping[str, ~typing.Any] = <factory>, development_col: str = 'development_month')[source]

Bases: Assumption

Claim completion factors in the divide convention, supplied or estimated.

class CredibilityAssumption(name: str, values: ~typing.Any, lookup: tuple[str, ...] | list[str] = <factory>, value_col: str | None = None, source: str = 'supplied', indicated_values: ~typing.Any | None = None, diagnostics: ~typing.Any | None = None, metadata: ~collections.abc.Mapping[str, ~typing.Any] = <factory>)[source]

Bases: Assumption

Credibility weights supplied or estimated by actuarialpy.

class DateCohort(name: str, date_col: str, split_date: Any | None = None, before_label: str = 'before', on_or_after_label: str = 'on_or_after', frequency: str | None = None, breaks: tuple[Any, ...] | None = None, labels: tuple[str, ...] | None = None, include_lowest: bool = True)[source]

Bases: object

Create a reportable classification from a date column.

class ExpenseProjection(expenses: DataFrame, projection_keys: tuple[str, ...] | list[str], expense_type_col: str, base_value_col: str, basis_col: str, base_date_col: str, horizon: ProjectionHorizon, trend: TrendAssumption, exposure: DataFrame | None = None, premium: DataFrame | None = None, claims: DataFrame | None = None, exposure_col: str = 'exposure', premium_col: str = 'premium', claims_col: str = 'projected_claims', dates: ProjectionDates | None = None)[source]

Bases: object

Project expenses on per-exposure, fixed-monthly, percent-of-premium, and percent-of-claims bases, one table for all four.

trend may be keyed by expense type, so “contractually flat” is a per-type choice: a zero-trend type projects at its base value while the types around it trend (see examples/expenses.py). The claims and premium inputs are keyed value streams joined on the projection keys and period — nothing requires the claims stream to contain claims, so a percentage of any per-period quantity (a claims subset such as hospital claims only, or another expense run’s output) is the same mechanism fed a different table. Percentage bases are not multiplied by active_fraction: proration is already embedded in the stream they reference, and prorating again would double count.

class GroupProjection(*, prospective_membership, seasonal_factors=None, current_premium, current_member_months, rate_action=0.0, plan_change=0.0, book_pmpm, claim_trend, exp_midpoint, prosp_midpoint, group_pmpm=None, group_claims=None, group_member_months=None, group_claim_count=None, credibility=None, full_credibility_claims=1082.0, pooling_pmpm=0.0, plan_affects_claims=True, renewal_prob=1.0)[source]

Bases: object

One group’s forward roll: premium and claims projected together on one membership.

Composes PremiumRollforward (the stored premium rolled forward by rate action and plan change) and PMPMProjection (the credibility-blended, trended, pooled claims PMPM) on the supplied monthly membership, then weights both by the renewal probability – a lapsed group books neither, so loss_ratio is unaffected by renewal_prob while expected_premium / expected_claims carry it. This is the unit BookProjection loops over the in-force book.

Exposes monthly (month, member-months, premium, claims – conditional on renewal), the conditional totals premium / claims / loss_ratio, and the renewal-weighted expected_premium / expected_claims; the full detail, including the claims and premium build-ups, sits on result (GroupProjectionResult).

Parameters:
  • prospective_membership (array-like) – Projected member-months by prospective month; the horizon everything else is evaluated on.

  • seasonal_factors (array-like, optional) – Monthly claim seasonality (averaging one); redistributes claims across months without changing the annual total.

  • current_premium (float) – The stored premium and its member-months – rolled forward, never rebuilt from experience.

  • current_member_months (float) – The stored premium and its member-months – rolled forward, never rebuilt from experience.

  • rate_action (float, optional) – Renewal rate action and plan-value change, as decimals.

  • plan_change (float, optional) – Renewal rate action and plan-value change, as decimals.

  • book_pmpm (float) – Book claims PMPM and annual trend, applied midpoint-to-midpoint between the experience and projection periods.

  • claim_trend (float) – Book claims PMPM and annual trend, applied midpoint-to-midpoint between the experience and projection periods.

  • exp_midpoint (float) – Book claims PMPM and annual trend, applied midpoint-to-midpoint between the experience and projection periods.

  • prosp_midpoint (float) – Book claims PMPM and annual trend, applied midpoint-to-midpoint between the experience and projection periods.

  • group_pmpm (optional) – The group’s own experience – the PMPM directly, or claims and member-months to derive it.

  • group_claims (optional) – The group’s own experience – the PMPM directly, or claims and member-months to derive it.

  • group_member_months (optional) – The group’s own experience – the PMPM directly, or claims and member-months to derive it.

  • group_claim_count (optional) – Credibility, or the claim count to derive it by limited fluctuation (default full-credibility standard 1082 claims).

  • credibility (optional) – Credibility, or the claim count to derive it by limited fluctuation (default full-credibility standard 1082 claims).

  • full_credibility_claims (optional) – Credibility, or the claim count to derive it by limited fluctuation (default full-credibility standard 1082 claims).

  • pooling_pmpm (float, optional) – Large-claim pooling charge per member-month, trended alongside claims.

  • plan_affects_claims (bool, optional) – Whether plan_change also scales claims (default True).

  • renewal_prob (float, optional) – Probability the group renews – supplied (e.g. from underwriting), not modelled here; weights the expected figures.

class PMPMProjection(*, book_pmpm, claim_trend, exp_midpoint, prosp_midpoint, group_pmpm=None, group_claims=None, group_member_months=None, group_claim_count=None, credibility=None, full_credibility_claims=1082.0, plan_factor=1.0, pooling_pmpm=0.0)[source]

Bases: object

The claims engine: credibility-blend, trend, plan-adjust, and add pooling.

Blends the group’s own PMPM against the book PMPM with credibility Z (limited fluctuation from the group’s claim count, capped at one, unless supplied), trends midpoint-to-midpoint, applies the plan factor, and adds the trended large-claim pooling charge:

\[\text{projected} = \bigl[Z \cdot \text{group} + (1 - Z) \cdot \text{book}\bigr] \cdot \text{trend} \cdot \text{plan} + \text{pooling} \cdot \text{trend}\]

Note the pooling charge is trended but not plan-adjusted. projected_pmpm is a rate per member-month; claims() turns it into monthly claim dollars on a membership vector, with optional seasonal factors (averaging one) that redistribute across months without changing the annual total. The full build-up sits on result (PMPMResult).

Parameters:
  • book_pmpm (float) – The book (manual) claims PMPM the blend shrinks toward.

  • claim_trend (float) – Annual claim trend, applied between the experience-period and projection-period midpoints.

  • exp_midpoint (float) – Annual claim trend, applied between the experience-period and projection-period midpoints.

  • prosp_midpoint (float) – Annual claim trend, applied between the experience-period and projection-period midpoints.

  • group_pmpm (optional) – The group’s experience PMPM, or claims and member-months to derive it.

  • group_claims (optional) – The group’s experience PMPM, or claims and member-months to derive it.

  • group_member_months (optional) – The group’s experience PMPM, or claims and member-months to derive it.

  • group_claim_count (optional) – Credibility, or the claim count to derive it by limited fluctuation (default full-credibility standard 1082 claims).

  • credibility (optional) – Credibility, or the claim count to derive it by limited fluctuation (default full-credibility standard 1082 claims).

  • full_credibility_claims (optional) – Credibility, or the claim count to derive it by limited fluctuation (default full-credibility standard 1082 claims).

  • plan_factor (float, optional) – Multiplicative plan-value adjustment on the blended PMPM.

  • pooling_pmpm (float, optional) – Large-claim pooling charge per member-month.

claims(membership, seasonal_factors=None)[source]

Projected claim dollars by prospective month.

class PremiumProjection(premium_data: DataFrame, projection_keys: tuple[str, ...] | list[str], exposure: DataFrame, horizon: ProjectionHorizon, current_rate_col: str = 'current_premium_rate', exposure_col: str = 'exposure', exposure_period_col: str = 'projection_period', renewal_date_col: str = 'renewal_date', recurring_rate_action_col: str | None = None, rate_actions: RenewalRateActions | None = None, dates: ProjectionDates | None = None)[source]

Bases: object

Project premium rates and premium using supplied exposure (member-months, policy months, and so on — see exposure_col).

A recurring action column is applied in every period marked is_renewal_period. A RenewalRateActions schedule is applied once in the period containing each supplied effective date. The adjusted rate is carried forward to all subsequent periods.

class PremiumRollforward(*, current_premium, current_member_months, rate_action=0.0, plan_change=0.0)[source]

Bases: object

Roll the stored premium forward by known factors – never rebuilt from losses.

projected_pmpm = (current_premium / current_member_months) * (1 + rate_action) * (1 + plan_change). Premium is level per member-month (it earns evenly), so premium() scales by the membership vector with no seasonal shape – unlike claims. Rebuilding premium from loss experience is ratingmodels’ job; this projects the figure the database already holds. The build-up sits on result (PremiumResult).

Parameters:
  • current_premium (float) – The stored premium and its member-months; their ratio is the current PMPM.

  • current_member_months (float) – The stored premium and its member-months; their ratio is the current PMPM.

  • rate_action (float, optional) – Renewal rate action and plan-value change, as decimals (default 0).

  • plan_change (float, optional) – Renewal rate action and plan-value change, as decimals (default 0).

premium(membership)[source]

Projected premium dollars by prospective month (level per member-month).

class ProjectionDates(entry_date: str | None = None, exit_date: str | None = None, renewal_date: str | None = None, issue_date: str | None = None, experience_start: str | None = None, experience_end: str | None = None, exposure_timing: str = 'whole_period')[source]

Bases: object

Column roles for lifecycle and actuarial dates.

class ProjectionHorizon(start: Any, periods: int | None = None, end: Any | None = None, frequency: str = 'monthly')[source]

Bases: object

A deterministic projection timeline.

Parameters:
  • start (Any) – First projection date. It is normalized to the beginning of the containing month, quarter, or year.

  • periods (int | None) – Number of projection periods. Supply either periods or end.

  • end (Any | None) – Last date to include. Supply either periods or end.

  • frequency (str) – "monthly", "quarterly", or "annual".

property midpoint: Timestamp

Mean period midpoint of the horizon.

This is the prospective rating midpoint used as the default credibility blend basis: manual and book rates are conventionally stated at this level.

to_frame() DataFrame[source]

Return one row per projection period.

exception ProjectionModelsError[source]

Bases: Exception

Base exception for projectionmodels.

class ProjectionResults(frame: ~pandas.DataFrame, measures: ~collections.abc.Mapping[str, ~projectionmodels.calculations.VariableDefinition], projection_keys: tuple[str, ...], component_keys: tuple[str, ...] = <factory>, assumption_audit_data: ~pandas.DataFrame | None = None, adjustment_audit_data: ~pandas.DataFrame | None = None)[source]

Bases: object

Detailed projection output with mathematically explicit aggregation rules.

classmethod combine(*results: ProjectionResults) ProjectionResults[source]

Combine compatible result sets column-wise on their common identifiers.

summarize(by: str | Iterable[str], *, measures: str | Iterable[str] | None = None) DataFrame[source]

Summarize measures without double-counting coarser-grain values.

A measure’s declared grain identifies where it is unique. Requested grouping fields outside that grain are retained, which permits an entity- level exposure to repeat once for each displayed claim type while still counting only once when claim type is omitted from the summary.

class RenewalRateActions(frame: DataFrame, projection_keys: tuple[str, ...] | list[str], effective_date_col: str = 'effective_date', rate_action_col: str = 'rate_action')[source]

Bases: object

One-time rate actions keyed by projection record and effective date.

rate_action values are decimal changes: 0.10 means a 10% increase. Each action is applied once in the projection period containing its effective date. Use a rate-action column on PremiumProjection instead when the same action should recur at every renewal anniversary.

to_projection_table(horizon: ProjectionHorizon) DataFrame[source]

Return actions keyed to the horizon’s projection periods.

class Scenario(name: str = 'baseline', adjustments: tuple[~projectionmodels.adjustments.Adjustment, ...] | list[~projectionmodels.adjustments.Adjustment] = <factory>)[source]

Bases: object

A named collection of ordered adjustments.

class SeasonalityAssumption(name: str, values: ~typing.Any, lookup: tuple[str, ...] | list[str] = <factory>, value_col: str | None = None, source: str = 'supplied', indicated_values: ~typing.Any | None = None, diagnostics: ~typing.Any | None = None, metadata: ~collections.abc.Mapping[str, ~typing.Any] = <factory>, season_col: str = 'season', frequency: str = 'M')[source]

Bases: Assumption

Normalized seasonal multipliers.

class TrendAssumption(name: str, values: ~typing.Any, lookup: tuple[str, ...] | list[str] = <factory>, value_col: str | None = None, source: str = 'supplied', indicated_values: ~typing.Any | None = None, diagnostics: ~typing.Any | None = None, metadata: ~collections.abc.Mapping[str, ~typing.Any] = <factory>)[source]

Bases: Assumption

Annual trend rate, supplied or fitted with actuarialpy.fit_trend().

factor(frame: DataFrame, months: Any) Series[source]

Resolve annual rates and return factors for scalar or row-wise months.

exception ValidationError[source]

Bases: ProjectionModelsError, ValueError

Raised when projection inputs are structurally invalid.

new_business(*, book_pmpm, claim_trend, exp_midpoint, prosp_midpoint, prospective_membership, manual_premium_pmpm, seasonal_factors=None, close_ratio=1.0, plan_change=0.0, pooling_pmpm=0.0) GroupProjectionResult[source]

A sold-but-new case: no experience, so claims are fully manual (credibility 0) and premium is the manual/target rate on projected membership; close_ratio plays the role of the renewal probability.