Skip to main content

easy_glm

EasyGLM fits GLMs. It is designed for insurance pricing and turns fitted rating factors into insurance rate tables. If you are an actuary, data scientist or analyst who wants to fit GLMs and produce insurance rate tables, you may find it useful too, but it is not a general-purpose GLM package. It is designed to be easy to use, and to produce insurance rate tables that are easy to read and understand.

Warning! This has been built with AI purely for myself as I had built up a store of random python scripts to help me do pricing work and I needed a more sensible way to reuse them in new projects. Bugs are likely!

Install

pip install easy_glm

To upgrade an existing installation, run pip install --upgrade easy_glm.

Open the workbench

Start the graphical workbench:

easy-glm-workbench

It opens EasyGLM in your browser, normally at http://127.0.0.1:8501. Keep this terminal open while you use the workbench.

You can also open it from a Python session:

import easy_glm

easy_glm.launch_workbench()
# Explicit port/headless settings (useful on Windows and remote shells):
easy_glm.launch_workbench(port=8501, headless=True)

To open a Polars or pandas dataframe that is already in memory:

easy_glm.launch_workbench(data=df)

The workbench opens with df loaded. Choose the target, weight and predictors on the Variables page, then define and fit the model on the Model page. Before fitting, Check predictors flags possible target leakage, highly related predictors and mostly missing columns using a training sample. Choose removals, review them, then Apply to update the table, Role JSON and model selections. launch_workbench() prints the exact URL to open (for example, http://127.0.0.1:8501).

Without a supplied dataframe, Project & data opens first. Browse for your data file, reopen a saved project JSON, or choose an example dataset. CSV, Parquet, Excel, Arrow/Feather and SAS (.sas7bdat) files are supported, with a file-path option for large files. The French motor example models claim frequency with Poisson; the Swedish motorcycle example models annual claim cost with Tweedie. Both include editable settings; click Fit model when ready.

From 0.460, Svelte is the default workbench. The launch commands above are unchanged; easy-glm workbench also opens it. The previous interface remains available with easy-glm-workbench --legacy-streamlit, or legacy_streamlit=True from Python. Its advanced preparation, leakage and detailed factor-design controls are not yet all available in the new interface.

To reopen a saved project later, pass its project file after the command:

easy-glm-workbench path/to/project.easyglm-project.json

Before closing or upgrading, download your project JSON to keep its settings, applied adjustments and named snapshots. Export a .easyglm scorer to keep the fitted rates. Reopening project JSON requires its source data and starts without fitted runs or session Undo history. Stop and restart the workbench after upgrading.

The workbench follows the same modelling pipeline as the Python API. It helps you assign column roles, prepare a reproducible train/holdout split, design and fit one or more models, inspect diagnostics, adjust rate tables, and export the result as Python, a scorer, Excel tables or a self-contained report. It does not fit anything until you select Fit model.

Explore shows observed rates and exposure together before fitting. Diagnostics includes training and holdout checks and permutation importance. In Rate tables, choose an adjustment from the dropdown to preview it, then click Apply adjustment to keep it. The original fit stays visible. Exports use applied results; Python reproduction scripts need a saved source-data file.

Design and fit Validate on training and holdout data
Model definition in the EasyGLM workbench Training and holdout diagnostics in the EasyGLM workbench

For the practical screen-by-screen route, see the workbench walkthrough. The examples index points to the shorter runnable scripts.

Fit a Poisson claim-count model

We will fit a Poisson claim count model using the good ol' French Motort Third Party claims frequency dataset. The dataset contains ClaimNb for claim count, Exposure for - uh - yeah no guesses there and insurance-y variables like DrivAge, Region, BonusMalus and Density.

As ever, we love a good train/test set. The code creates a traintest column: 70% of rows teach the model; the other 30% are kept for the check at the end.

import easy_glm

# Downloads the public data once and reuses the local copy later.
df = easy_glm.load_external_dataframe().sample(n=50_000, seed=42)
df = easy_glm.add_train_test_split(df, train_fraction=0.7, seed=42)

predictors = ["DrivAge", "Region", "BonusMalus", "Density"]
model = easy_glm.EasyGLM.fit(
    data=df,
    target="ClaimNb",
    model_type="Poisson",
    predictors=predictors,
    weight_col="Exposure",
    train_test_col="traintest",
    divide_target_by_weight=True,
    cv=5,
)

See the fitted relativity tables

The base claim frequency is the starting level. A relativity of 1.20 means 20% more expected claims than a relativity of 1.00, after taking account of the other fitted factors. exposure shows how much insured time informed each row of the table.

print(f"Base claim frequency: {model.base_rate:.5f} claims per policy-year")
for name, table in model.relativities.items():
    print(f"\n{name}")
    print(table.select("label", "relativity", "exposure"))

The output includes numeric bands and text levels. These are representative rows from the fitted French motor model:

Base claim frequency: 0.04167 claims per policy-year

BonusMalus
band            relativity   exposure
< 53.0            1.000        12108.31
[53.0, 57.0)      1.355          790.70
[57.0, 60.0)      1.830          694.10

Region
level                         relativity   exposure
Centre                          1.000       5218.59
Rhone-Alpes                     1.356       2312.63
Provence-Alpes-Cotes-D'Azur     1.177       1835.53

Plot the fitted shapes

Run the following to open the fitted shapes, then the training and test actual-versus-expected rate charts. The validation charts use the exact fitted bands or category order, draw Actual in red and Expected in blue, and show Exposure behind the rate lines.

easy_glm.plot_all_ratetables(model.relativities)
model.plot_actual_vs_expected(df)

These representative images were generated by that example. Expected rates use the complete fitted model, not just the factor named on the figure.

Fitted BonusMalus relativity shape

BonusMalus test actual versus expected rate

Fit the same model in the workbench

You can send the French motor data straight from Python to the graphical workbench:

import easy_glm

df = easy_glm.load_external_dataframe().sample(n=50_000, seed=42)
easy_glm.launch_workbench(data=df)

The workbench opens with the data loaded but makes no modelling decisions for you. The workbench walkthrough shows how to assign the roles, create the split, fit this Poisson model, compare a challenger, review training and holdout diagnostics, and export the reproducible workflow.

Fit a Tweedie incurred-claims model

The Poisson model predicts how many claims will occur. A Tweedie model can instead predict the total cost of claims, including policies with no claims.

This example uses the public Swedish motorcycle portfolio. It contains ClaimAmount, the total claim payments; Exposure, the number of policy years; and six rating factors. EasyGLM downloads it once and keeps a local copy for later runs.

import polars as pl

# Download the Swedish motorcycle data and remove rows with no exposure.
df = easy_glm.load_swedish_motorcycle_data()
df = df.filter(pl.col("Exposure") > 0)
df = easy_glm.add_train_test_split(df, train_fraction=0.7, seed=42)

model = easy_glm.EasyGLM.fit(
    data=df,
    target="ClaimAmount",
    model_type="Tweedie",
    predictors=[
        "OwnerAge",
        "Gender",
        "Area",
        "RiskClass",
        "VehAge",
        "BonusClass",
    ],
    weight_col="Exposure",
    train_test_col="traintest",
    divide_target_by_weight=True,
    tweedie_power=1.5,
    cv=5,
)

The target divided by exposure is annual incurred claim cost. The Tweedie power is fixed at 1.5 for this first example; automatic power selection is on the future-release list.

The fitted rate tables and the training and holdout checks work in exactly the same way as in the Poisson example:

print(f"Base annual claim cost: {model.base_rate:.2f}")
for name, table in model.relativities.items():
    print(f"\n{name}")
    print(table.select("label", "relativity", "exposure"))

easy_glm.plot_all_ratetables(model.relativities)
model.plot_actual_vs_expected(df)

These representative graphs were generated by the Tweedie example above. The expected annual claim costs use the complete fitted model, not just the factor shown on each graph.

Fitted owner-age relativity shape

Owner-age holdout actual versus expected annual claim cost

Both walkthroughs are also available together in the standalone basic usage example. See the changelog for a plain-English summary of each release.

MIT licensed. See LICENSE.

Release files for easy-glm 0.461

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for easy-glm 0.461
File Size Uploaded
easy_glm-0.461.tar.gz 598.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for easy-glm 0.461
File Interpreter ABI Platform
easy_glm-0.461-py3-none-any.whl Python 3 none any Details

Total release size: 1.0 MB

Release files / easy_glm-0.461.tar.gz

Download URL easy_glm-0.461.tar.gz
Size 598.8 kB
Tags Source
SHA-256 checksum
How to use checksums
8103c2dc00e8de146754764db21a80390c316e2a955e54086074f9960ce0c5e7
BLAKE2b-256 checksum
How to use checksums
9a3b9519db75c113b525a1d03b84f3ffc30f1a308dce25c273002f81a8fa04fd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / easy_glm-0.461-py3-none-any.whl

Download URL easy_glm-0.461-py3-none-any.whl
Size 428.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bdf887579bf6e5fcd501bb20de1ed901b58a4be55877aebbcb83c9f94d522dec
BLAKE2b-256 checksum
How to use checksums
2172b9d170d74c0bb1af32ccee42dcd2d55540497d347dd6747ef6c8b29e1cd0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release history Release notifications | RSS feed

0.471

2 release files

0.470

2 release files

0.464

2 release files

0.463

2 release files

0.462

2 release files

This release

0.461 This release

2 release files

0.460

2 release files

0.452

2 release files

0.451

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page