Focused actuarial claim, premium, membership, and expense projections.
Project description
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.
Installation
pip install projectionmodels
projectionmodels currently supports actuarialpy>=0.41,<0.45 and Python
3.10–3.13.
Public API
The package root contains the workflow objects most actuaries need:
ClaimExperience Prepare a base claim rate from 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.
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": group_id,
"projection_period": period,
"member_months": 1_000.0,
}
for group_id in ("A", "B")
for period in periods
]
)
results = pm.PremiumProjection(
premium_data=premium_data,
projection_keys=["group_id"],
exposure=exposure,
exposure_col="member_months",
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 in March, and carries that rate forward. Group B increases to $120 in July.
For different actions at different renewals, provide an effective-dated table:
actions = pm.RenewalRateActions(
pd.DataFrame(
{
"group_id": ["A", "A", "B"],
"effective_date": pd.to_datetime(
["2027-03-01", "2028-03-01", "2027-07-01"]
),
"rate_action": [0.10, 0.06, 0.20],
}
),
projection_keys=["group_id"],
)
Claims by claim type
experience = pm.ClaimExperience(
claims,
projection_keys=["group_id", "product_id"],
claim_type_col="claim_type",
date_col="incurred_month",
claims_col="reported_claims",
exposure_col="member_months",
valuation_date="2026-12-31",
)
projection = pm.ClaimProjection.from_experience(
experience,
exposure=exposure,
exposure_col="member_months",
horizon=pm.ProjectionHorizon("2027-01-01", periods=36),
completion=completion,
trend=trend,
seasonality=seasonality,
credibility=credibility,
complement=manual_rates,
)
results = projection.project()
Trend, seasonality, completion, and credibility may be supplied directly as assumption tables.
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:
from projectionmodels.integrations.actuarialpy import (
estimate_completion,
estimate_credibility,
estimate_seasonality,
estimate_trend,
)
completion = estimate_completion(
"claim_completion",
payment_history,
by=["claim_type"],
origin_col="incurred_month",
valuation_col="paid_month",
amount_col="paid_claims",
)
seasonality = estimate_seasonality(
"claim_seasonality",
completed_history,
by=["claim_type"],
date_col="incurred_month",
value_col="completed_claims",
exposure_col="member_months",
)
trend = estimate_trend(
"claim_trend",
deseasonalized_history,
by=["claim_type"],
date_col="incurred_month",
value_col="deseasonalized_claims",
exposure_col="member_months",
)
credibility = estimate_credibility(
"claim_credibility",
experience_history,
method="limited_fluctuation",
by=["group_id", "claim_type"],
exposure_col="claim_count",
full_credibility_standard=2_000,
)
The returned assumptions retain indicated values and diagnostics. An actuary can replace the indication while preserving the audit trail:
selected_trend = trend.select(selected_table, note="2027 pricing selection")
Expenses
ExpenseProjection supports:
per_exposurefixed_monthlypercent_premiumpercent_claims
Each expense type may have its own trend and projection component.
Date handling
ProjectionDates supports entry, exit, renewal, issue, and experience dates.
Records can be inactive before entry or after exit, and exposure can be whole-
period or daily-prorated.
DateCohort adds reportable classifications such as existing versus new
business:
records = pm.DateCohort(
"business_origin",
"effective_date",
split_date="2027-01-01",
before_label="existing",
on_or_after_label="new_business",
).apply(records)
Results
summary = results.summarize(
by=["scenario", "product_id", "calendar_year"],
measures=["member_months", "premium", "projected_claims", "claims_per_exposure"],
)
ProjectionResults retains measure grain. It counts exposure once when claim
type is removed from a summary and recalculates per-exposure rates and loss ratios from their
summed numerators and denominators.
Advanced models
Custom deterministic roll-forwards remain available, but are deliberately moved out of the primary namespace:
import projectionmodels.advanced as pma
model = pma.ProjectionModel(...)
Use this only when the claim, premium, and expense workflows are insufficient. The advanced API remains provisional while the concrete workflows stabilize.
Examples
Primary examples:
examples/health_claims.py
examples/pooled_claims.py
examples/calculated_assumptions.py
examples/renewal_rate_actions.py
examples/date_cohorts.py
examples/expenses.py
examples/underwriting_results.py
Custom-engine examples are under examples/advanced/.
Testing
The test suite imports the installed actuarialpy; it does not replace it with a
session-wide fake. CI runs the tests, every example, package builds, and a clean
wheel-install smoke test.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file projectionmodels-0.6.2.tar.gz.
File metadata
- Download URL: projectionmodels-0.6.2.tar.gz
- Upload date:
- Size: 66.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a91bc11875eac5be7d7d2768ac88ecfdbb09aa119a8161fab479aca666d6014
|
|
| MD5 |
b3fc8cce8601ec23bd2915138f5f4d61
|
|
| BLAKE2b-256 |
7ffdd14bf4f37ad7e102c733fb82b91481aca5e7ab2576685bf3b701245dfb74
|
Provenance
The following attestation bundles were made for projectionmodels-0.6.2.tar.gz:
Publisher:
release.yml on OpenActuarial/projectionmodels
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
projectionmodels-0.6.2.tar.gz -
Subject digest:
6a91bc11875eac5be7d7d2768ac88ecfdbb09aa119a8161fab479aca666d6014 - Sigstore transparency entry: 2134245992
- Sigstore integration time:
-
Permalink:
OpenActuarial/projectionmodels@6d75cf9111c748041c0ba6b5dab7112e3487fa2e -
Branch / Tag:
refs/tags/v0.6.2 - Owner: https://github.com/OpenActuarial
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6d75cf9111c748041c0ba6b5dab7112e3487fa2e -
Trigger Event:
push
-
Statement type:
File details
Details for the file projectionmodels-0.6.2-py3-none-any.whl.
File metadata
- Download URL: projectionmodels-0.6.2-py3-none-any.whl
- Upload date:
- Size: 44.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d73bd7f2270aae59328f84a0280a8e0044b1847206d22a64dc6d4fbd75615db7
|
|
| MD5 |
f71005b9ead7bcf90e29b43bc8b9c81f
|
|
| BLAKE2b-256 |
2494b7e4bdfee4127e8d07dba05ddac071557173922efaa614721e8ab57ebd58
|
Provenance
The following attestation bundles were made for projectionmodels-0.6.2-py3-none-any.whl:
Publisher:
release.yml on OpenActuarial/projectionmodels
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
projectionmodels-0.6.2-py3-none-any.whl -
Subject digest:
d73bd7f2270aae59328f84a0280a8e0044b1847206d22a64dc6d4fbd75615db7 - Sigstore transparency entry: 2134246032
- Sigstore integration time:
-
Permalink:
OpenActuarial/projectionmodels@6d75cf9111c748041c0ba6b5dab7112e3487fa2e -
Branch / Tag:
refs/tags/v0.6.2 - Owner: https://github.com/OpenActuarial
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6d75cf9111c748041c0ba6b5dab7112e3487fa2e -
Trigger Event:
push
-
Statement type: