Metadata-Version: 2.4
Name: experiencestudies
Version: 0.3.0
Summary: Experience reporting and analysis on tidy tables: experience summaries and views, actual-versus-expected, claimant and cohort studies, driver and frequency-severity decomposition, rolling monitors, banded summaries, and the fluent Experience object. Built on actuarialpy.
Project-URL: Homepage, https://github.com/OpenActuarial/experiencestudies
Project-URL: Documentation, https://openactuarial.org/experiencestudies.html
Project-URL: Repository, https://github.com/OpenActuarial/experiencestudies
Project-URL: Issues, https://github.com/OpenActuarial/experiencestudies/issues
Author: Michael Bryant
License-Expression: MIT
License-File: LICENSE
Keywords: actuarial,analytics,claims,experience analysis,insurance,loss ratio,risk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Scientific/Engineering :: Mathematics
Requires-Python: >=3.10
Requires-Dist: actuarialpy>=0.42
Requires-Dist: numpy>=1.23
Requires-Dist: pandas>=1.5
Provides-Extra: dev
Requires-Dist: build>=1; extra == 'dev'
Requires-Dist: hypothesis>=6; extra == 'dev'
Requires-Dist: openpyxl>=3.1; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: twine>=5; extra == 'dev'
Provides-Extra: excel
Requires-Dist: openpyxl>=3.1; extra == 'excel'
Description-Content-Type: text/markdown

# experiencestudies

[![CI](https://github.com/OpenActuarial/experiencestudies/actions/workflows/ci.yml/badge.svg)](https://github.com/OpenActuarial/experiencestudies/actions/workflows/ci.yml) [![PyPI](https://img.shields.io/pypi/v/experiencestudies)](https://pypi.org/project/experiencestudies/)

Experience reporting and analysis on claims, exposure, and premium data: experience
summaries and views, actual-versus-expected, claimant and concentration analysis, cohort
and duration studies, driver and frequency-severity decomposition, rolling monitors,
banded summaries, and simple forecasting — tied together by the fluent `Experience`
object. Built on [`actuarialpy`](https://github.com/OpenActuarial/actuarialpy), which
supplies the underlying primitives (ratios, trend, credibility, completion, seasonality,
financial mathematics). Every result is a DataFrame or Series.

## Contents

- [Overview](#overview)
- [Installation](#installation)
- [Quick start](#quick-start)
- [The `Experience` object](#the-experience-object)
- [Experience summaries and views](#experience-summaries-and-views)
- [Actual versus expected and forecasting](#actual-versus-expected-and-forecasting)
- [Claimant and concentration analysis](#claimant-and-concentration-analysis)
- [Cohort and duration studies](#cohort-and-duration-studies)
- [Driver and frequency-severity decomposition](#driver-and-frequency-severity-decomposition)
- [Rolling monitors](#rolling-monitors)
- [Banded summaries](#banded-summaries)
- [Underwriting income statement](#underwriting-income-statement)
- [Reporting](#reporting)
- [Relationship to actuarialpy](#relationship-to-actuarialpy)

## Overview

`experiencestudies` is the study layer that sits on top of the `actuarialpy` primitives.
Where `actuarialpy` answers "what is the loss ratio / development factor / credibility
weight for this table?", `experiencestudies` answers "how is this block performing, why is
it moving, and where is the risk concentrated?". It does not perform data preparation or
encode filed methodology: the caller supplies the tidy table and selects the analysis.

There are two interfaces:

- **Free functions** — `summarize_experience`, `summarize_actual_vs_expected`,
  `summarize_claimants`, `cohort_summary`, `decompose_per_exposure_trend`,
  `frequency_severity_summary`, `rolling_summary`, `summarize_by_band`, and the
  forecasting helpers. Each takes a DataFrame and returns a DataFrame.
- **The `Experience` object** — a fluent wrapper that remembers the expense, revenue,
  exposure, and date columns once, then exposes the same analyses as chainable methods
  (`.by()`, `.rolling()`, `.deseasonalize()`, `.complete()`, `.adjust()`, ...), each
  returning a new `Experience` so restatements compose.

## Installation

```bash
pip install experiencestudies
```

This pulls in `actuarialpy` (>= 0.42) automatically. For the Excel report writer, install
the `excel` extra:

```bash
pip install "experiencestudies[excel]"
```

## Quick start

```python
import pandas as pd
from experiencestudies import Experience, summarize_experience

df = pd.DataFrame({
    "month": pd.date_range("2024-01-01", periods=12, freq="MS"),
    "lob": ["med"] * 12,
    "claims": [820, 910, 875, 1010, 990, 1105, 1080, 1240, 1180, 1035, 995, 1150.0],
    "premium": [1500] * 12,
    "member_months": [1000] * 12,
})

# free-function form
summary = summarize_experience(
    df, groupby="lob",
    expense_cols="claims", revenue_cols="premium", exposure_cols="member_months",
)

# fluent form — same result, plus composable views
exp = Experience(df, expense="claims", revenue="premium",
                 exposure="member_months", date="month")
by_lob = exp.by("lob")
trailing = exp.rolling(3)
```

## The `Experience` object

Construct once with the column roles, then chain. Each method returns a new `Experience`
(or a summary DataFrame for the terminal views), so adjustments and restatements compose
without mutating the source:

```python
restated = (
    exp.adjust(1.03)                      # apply a 3% trend/restatement factor
       .deseasonalize(seasonal_factors)   # divide out a seasonal shape
       .complete(completion_factors, valuation_date="2024-12-31")  # gross up to ultimate
)
restated.by("lob")                        # terminal summary
```

The seasonal factors and completion factors come from `actuarialpy`
(`seasonality_factors`, `completion_factors`); `experiencestudies` applies them through
the fluent lens.

## Experience summaries and views

`summarize_experience` and the `Experience.by()` / `.views()` methods produce grouped
aggregates with loss ratio and per-exposure metrics. `status_summary` and
`summarize_views` give status- and view-oriented cuts of the same underlying rollup.

## Actual versus expected and forecasting

`summarize_actual_vs_expected` compares realized experience against an expected column.
`expected_from_rate` and `forecast_from_rate` build expected/forecast values from a rate
basis; `forecast_experience` projects an experience frame forward; and
`compare_actual_to_expected` reports the variance.

## Claimant and concentration analysis

`summarize_claimants`, `top_claimants`, `large_claimant_flags`, and `claim_concentration`
identify and rank large claimants and measure how concentrated losses are (e.g. the share
carried by the top *n*).

## Cohort and duration studies

`cohort_summary`, `cohort_summary_by_period`, and `duration_summary` track experience by
entry cohort and by duration since entry.

## Driver and frequency-severity decomposition

`component_driver_analysis`, `component_trend`, and `summarize_components` attribute
movement to its components; `decompose_per_exposure_trend` splits a per-exposure trend into
frequency and severity contributions, and `frequency_severity_summary` reports the two
sides side by side.

## Rolling monitors

`rolling_summary` (and `Experience.rolling(window)`) produce trailing-window rollups for
monitoring emerging experience.

## Banded summaries

`summarize_by_band` assigns rows to size bands (via `actuarialpy.assign_band`) and
summarizes experience within each band, preserving band order and surfacing empty bands.

## Underwriting income statement

`underwriting_summary` (and the `UnderwritingSummary` object) build the two-tier
underwriting result — **gross margin** (revenue less loss expense, operating expense
excluded) and **gain/(loss)** (gross margin less operating expense) — with each ratio's
denominator an explicit parameter, since real exhibits mix them (a loss ratio over net
revenue beside an expense ratio over gross premium). Component labels and the output ratio
name are the caller's vocabulary: the library only sums the components, and domain naming
(a health shop's `mlr`, a life shop's `benefit_ratio`) is applied on the output views via
`profile` / `labels`, never in the calculation.

```python
from experiencestudies import underwriting_summary

underwriting_summary(df, groupby="cohort",
                     revenue_cols=["premium", "refund"], loss_cols=claim_cols,
                     expense_cols="expense", exposure_col="member_months",
                     premium_col="premium")
```

## Reporting

`to_excel_report` writes a dict of named views to a multi-sheet Excel workbook (one sheet
per key). The values are plain DataFrames, so any summary you produce — grouped
experience, an underwriting statement, a rolling monitor — can be a sheet:

```python
from experiencestudies import to_excel_report

to_excel_report(
    {"overall": overall_summary, "by_group": by_group_summary},
    "report.xlsx",
)   # requires the `excel` extra (openpyxl)
```

## Relationship to actuarialpy

`experiencestudies` depends on `actuarialpy` and never the other way around — the
dependency is strictly one-directional. The size-banding split is the clearest example:
the `assign_band` primitive lives in `actuarialpy`, while `summarize_by_band` (which needs
an experience summary) lives here. Because the study layer imports from the primitive
layer, publish a compatible `actuarialpy` (>= 0.42) before releasing a new
`experiencestudies`.
