Vintage Analysis Tutorial
This guide shows the baseline vintage workflow for comparing smoothing methods, validating them, and optionally projecting incomplete vintage tails.
Front door: the single deep entry point is
vintage.run() in cranalytics.vintage._session, which runs
triangle construction, smoothing comparison, ranking, and validation in one
call. Reach for the lower-level cranalytics.vintage helpers only when you
need a narrower step. The cranalytics.vintage package __init__.py is a
compatibility re-export surface, not a place where logic lives.
Use this workflow when
- you have cohort-level loss history by month on book
- you want a fast cumulative-loss workflow without building a transition model
- you need a ranked smoothing comparison as the first success metric
Do not start here if
- your starting object is a portfolio snapshot plus a transition matrix — use Lifetime Loss Forecasting
- your starting object is monthly aggregated rollforward data — use the Rollforward workflow
- your main question is time-to-default or prepayment timing — use Survival Analysis
Inputs
Minimum columns:
vintage_datemonths_on_bookcumulative_loss_rate
Useful segmentation columns:
vintage_nameif you plan to overridevintage_colsegment
If your data uses older labels such as vintage_name and mob, pass them
through vintage.run(..., vintage_col=..., mob_col=...).
Tip
Start with the session boundary before choosing one smoothing method. It compares methods, validates them, and can project incomplete tails.
For the full contract, see Input Data Contracts.
Code
import numpy as np
import pandas as pd
from cranalytics import vintage
rows = []
for vintage_name, max_mob in [("2022-Q1", 12), ("2022-Q2", 9)]:
curve = np.maximum.accumulate(
0.055 * (1.0 - np.exp(-np.arange(1, max_mob + 1) / 6.0))
)
for mob, value in enumerate(curve, start=1):
rows.append(
{
"vintage_date": vintage_name,
"months_on_book": mob,
"cumulative_loss_rate": float(value),
}
)
session = vintage.run(
pd.DataFrame(rows),
min_maturity_months=12,
extrapolate_tails=True,
)
print(session.rankings[["method_name", "score"]])
print(session.validation_summary[["method_name", "train_mse", "test_mse"]])
print(session.tail_projections.tail())
Expected output / first win
Your first win is a vintage analysis session result with method rankings, validation output, and optional projected tails for incomplete vintages.
You should expect:
- a ranked smoothing comparison table
- a validation summary across smoothing methods
- optional
tail_projectionsrows when incomplete vintages are present andextrapolate_tails=True
Visualization
Visualize your vintage curves using the plotting utilities.
from cranalytics.viz import plot_vintage_triangle
import pandas as pd
triangle = pd.DataFrame(
{
1: [0.01, 0.008],
2: [0.02, 0.018],
3: [0.03, 0.027],
},
index=["2022-Q1", "2022-Q2"],
)
fig = plot_vintage_triangle(triangle)
fig.show()
Common mistakes
- Passing a wide pivoted table without first reshaping it into long vintage observations.
- Feeding a non-cumulative loss series into a cumulative-loss workflow.
- Expecting this workflow to model cashflows, transitions, or dynamic status migration.
- Jumping straight to a single fitter before checking whether the session boundary already covers comparison, validation, and tail projection.
- Using Vintage when your real business question is about feature ranking or ML backtesting.
Next step
Run the packaged demo end-to-end with:
python -m cranalytics.examples.core_vintage
If you only need one direct parametric curve fit instead of the full analysis
session, use CurveFitter from cranalytics.vintage.
If you need reserve-style portfolio forecasting instead of cohort curve fitting, continue to the Lifetime Loss Forecasting Tutorial.