Triangle class

class bermuda.triangle.Triangle(cells: Sequence[Cell])

The main triangle class.

The Triangle class inherits from collections.abc.Set. It holds a sequence of Cell objects, which are automatically sorted on class instance creation.

The Triangle class has a number of methods, properties and static methods for triangle manipulation, visualization, and I/O. Consult the documentation for more details.

cells

the sequence of Cell objects.

add_statics(source: Triangle, statics: list[str] = ['earned_premium', 'earned_exposure']) Triangle

Add “static” fields to a Triangle. Some fields (for example, accident-period earned premium) can be considered as fixed with respect to development lag. This method takes static fields from one triangle and adds them to another triangle. For example, if we have a triangle of predicted paid_loss and another disjoint triangle with observed paid_loss, we can fill in earned_premium values in the former triangle with values from the latter triangle. :param source: A Triangle that will be used to fill in static fields. :param statics: A list of field names to fill in.

Returns:

A Triangle with static fields filled in from source.

aggregate(period_resolution: tuple[int, str] | None = None, eval_resolution: tuple[int, str] | None = None, period_origin: date = datetime.date(1999, 12, 31), eval_origin: date = datetime.date(1999, 12, 31), summarize_premium: bool = True) Triangle[Cell]

Change the period and/or evaluation resolution of a triangle.

Period resolution is defined as the length of each experience period in a triangle. Similarly, evaluation resolution is defined as the interval between each successive evaluation date in a triangle. Period resolution and evaluation are commonly equal to each other, but this is not a hard requirement.

This aggregation implementation will not try to interpolate, apportion, or otherwise estimate triangle cells when data is insufficient to determine an exact answer. This means that if a triangle has two experience periods, 2020-01-01:2020-09-30 and 2020-10-01:2021-06-30, aggregation to annual data is not possible.

Aggregation over experience periods is equivalent to summing all values from all cells that are being merged into a new cell. No warnings are issued if not all cells have the same set of attributes, or if the new experience period isn’t completely covered by merged cells. Depending on the semantics of your source data and intended application, this may not be advisable.

Aggregation over evaluation dates is equivalent to filtering out evaluation dates. No effort is made to “carry forward” cells with gaps in their evaluation date history. The aggregation strategy is to sum fields over cells. This makes sense for fields such as paid loss, earned premium, and claim counts, but aggregation-by-summation doesn’t make sense for fields such as loss ratio or average claim severity. This function does not attempt to infer an appropriate aggregation strategy based on the name of each field.

Parameters:
  • triangle – Triangle to aggregate.

  • period_resolution – If supplied, the length of each experience perid. Format is a tuple with an integer number of units and a string specifying the unit. E.g., (7, “day”), (3, “months”), (1, “year”). If missing, no experience period aggregation will be performed.

  • eval_resolution – If supplied, the interval between each evaluation date. Format is the same as for period_resolution. If missing, no evaluation date aggregation will be performed.

  • period_origin – A date that will be guaranteed to be a period start date (if there is any contemporaneous data). This argument is used for offseting experience periods temporally: e.g., for annual experience periods that start on July 1 of each year, supply period_origin=datetime.date(2000, 7, 1) or similar.

  • eval_origin – A date that will be guaranteed to be an evaluation date (if there is any contemporaneous data). See period_origin for details of semantics.

  • summarize_premium – Whether or not to sum up premiums over aggregated cells. Defaults to True, set to False when summarizing over loss details over which premiums should not be summed.

blend(weights: list[float] | dict[str, ndarray] | None = None, method: Literal['mixture', 'linear'] = 'mixture', seed: int | None = None) Triangle

Return a weighted blend of triangles by their values.

There are two distinct methods of blending. Mixture blending samples cell values in proportion to their weight. Linear blending is a linear weighted average of the cell values. Mixture blending only applies to distributions of cell values with the same dimensions, but linear blending can be applied between distributions and scalars alike.

Parameters:
  • triangles – The list of triangles to blend.

  • weights – The optional list or dictionary of weights. Cell-wise weights are passed as a dictionary.

  • method – The blending method to use. Can be one of [‘mixture’, ‘linear’]. Defaults to mixture.

  • seed – The seed to use for mixture blending.

Returns:

A blended triangle.

clip(*, min_eval: date | None = None, max_eval: date | None = None, min_period: date | None = None, max_period: date | None = None, min_dev: timedelta | int | float | None = None, max_dev: timedelta | int | float | None = None, dev_lag_unit: str = 'month') Triangle

Create a new Triangle that has been clipped/censored as specified.

Parameters:
  • min_eval – Minimum evaluation date to permit.

  • max_eval – Maximum evaluation date to permit.

  • min_period – Minimum period start date to permit.

  • max_period – Maximum period end date to permit.

  • min_dev – Minimum development lag to permit.

  • max_dev – Maximum development lag to permit.

  • dev_lag_unit – Unit of min_dev or max_dev, required if either is specified.

coalesce() Triangle

Coalesce triangle cells from a list of Triangles such that the resulting triangle is a union of the cells from each triangle. Matching cells in the earlier triangles in the triangle list take precedence over cells from later triangles.

coalesce is different from merge in that it only keeps the fields and values from the cell with precedence, wheras merge will return the union of fields across the matching cells.

Parameters:

triangles – A list of Triangle whose cells will be coalesced.

Returns:

A Triangle with Cells at all coordinates of the triangles in the triangle list.

property common_metadata: Metadata

A single metadata element representing the metadata attributes common to all Cells in the Triangle.

derive_fields(**definitions: Callable[[Cell], Any] | Any) Triangle

Create a new Triangle with additional derived fields defined.

Parameters:

**definitions – New field definitions. Argument names are the names of the new fields to be defined, values are either constants or functions that accept cells and return field values. Later definitions can depend on quantities computed via earlier definitions.

derive_metadata(**definitions: Callable[[Cell], Any] | Any) Triangle

Create a new Triangle with additional metadata attributes or fields derived.

Parameters:

**definitions – Values are plain values or functions that accept a Cell and return a value. If keys are top-level attributes in metadata, their values will replace the existing values of the top-level attributes. Otherwise, the key-value pair will be added to the details field of the metadata.

dev_lags(unit='month') list[float | int | timedelta]

A sorted list of unique development lags. unit can be, ‘month’, ‘day’ or ‘timedelta’. See docs for Observation.dev_lag() or Prediction.dev_lag() for more information.

property eval_date_resolution: int

The resolution of the evaluation dates in the triangle.

property evaluation_date: date

The latest evaluation date in the triangle.

property evaluation_dates: list[date]

A sorted list of unique evaluation dates.

property experience_gaps: list[tuple[date, date]]

A sorted list of missing experience period ranges from the triangle

extract(attribute: Callable[[Cell], Any] | str) ndarray

Extract cell attributes either via a function or cell field name, returning a numpy array of values.

Parameters:

attribute – A function applied to all cells or a cell field.

property field_cell_counts: dict[str, int]

For each triangle field return the number of cells the field appears in.

property field_slice_counts: dict[str, int]

For each triangle field return the number of slices the field appears in.

property fields: list[str]

A sorted list of unique fields in the triangle set.

filter(predicate: Callable[[Cell], bool]) Triangle

Create a new Triangle with only the cells that satisfy the predicate.

Parameters:

predicate – A function that accepts a Cell and returns a boolean.

static from_array_data_frame()

Convert a DataFrame in a triangular array format to a Triangle object. The first column is assumed to contain the accident or policy period. This should be a date, or a string that can be parsed as a date (e.g. “2020”, or “2020Q1”). All subsequent columns are assumed to contain values for the development periods. If integer development lags cannot be inferred from the column names an eval_resolution should be provided.

Parameters:
  • df – DataFrame in a triangular array format.

  • field – Field name.

  • period_resolution – Period resolution in months. If None, this is inferred from the first consecutive period dates.

  • eval_resolution – Evaluation resolution in months. If None, this is inferred from the column names. If None and column names are missing, it’s assumed to be the same as period_resolution.

  • dev_lag_from_period_end – Is the development lag calculated from the period_end rather than the period start? The bermuda convention is to calculate dev lags as the number of months from the end of the period (so the first natural evaluation for any period is lag 0). If False, the dev lag is calculated from the period start.

  • metadata – Metadata associated with the triangle.

static from_binary()

Read a Bermuda triangle from Bermuda’s binary file format.

Parameters:
  • filename – The filename to read the triangle from.

  • compress – Whether the source file is compressed. If not provided explicitly, compression will be inferred from the file extension.

static from_chain_ladder()

Create a Triangle from a chainladder Triangle object.

Anything in the chainladder index will become details in the Bermuda Triangle.

Parameters:
  • chain_ladder (chainladder.core.triangle.Triangle) – The chainladder Triangle object.

  • base_metadata (Metadata) – The base metadata to apply to all cells. Defaults to None.

Returns:

The Bermuda Triangle.

Return type:

Triangle

static from_long_csv()

Convert a long-format CSV to a Triangle.

For more details on long-format CSVs/tables, see long_data_frame_to_triangle (which this function is a thin wrapper for).

Parameters:
  • file_or_fname – Name of the CSV file or a handle to a file object.

  • detail_cols – Names of the columns that should be interpreted as metadata details. At least one of field_cols or detail_cols must be supplied.

  • loss_detail_cols – Names of the metadata columns that should be interpreted as metadata loss details, rather than standard metdata details. By default, nothing is assumed to be a loss detail.

  • **kwargs – Extra arguments to pd.read_csv

static from_long_data_frame()

Convert a long-format pd.DataFrame to a Triangle.

A long-format DataFrame requires the following columns to be present: period_start, period_end, evaluation_date, field and value. When the column ‘prev_evaluation_date’ is present, a triangle with incremental cells is generated. Otherwise, all triangle cells are cumulative.

Each row of the DataFrame represents a field of a single Cell of the Triangle. Any columns besides the three required columns are interpreted as metadata (i.e., per_occurrence_limit, currency, program_name).

The metadata argument can be used to supply common metadata that may not be directly present in the DataFrame. For example, every Cell in the Triangle could be accident-basis, gross of reinsurance, including DCC. This could be supplied by a single Metadata object in the function call instead of adding several constant columns to the DataFrame.

Parameters:
  • df – Pandas DataFrame to convert to a Triangle.

  • loss_detail_cols – List of columns that belong to loss_details in Metadata, rather than details.

  • metadata – Default metadata to apply to every cell in the Triangle.

static from_statics_data_frame()

Convert a DataFrame in a “statics” format to a Triangle object. The first column is assumed to contain the accident or policy period. This should be a date, or a string that can be parsed as a date (e.g. “2020”, or “2020Q1”). All subsequent columns are assumed to contain values for a single development period that are typically assumed to be static over development periods (e.g. earned premium, earned exposure). In order to convert these values into a triangle an evaluation_date must be provided. If the resulting triangle can often be added to an existing loss triangle using the add_statics function, in which case the evaluation_date is just a placeholder (though this must be greater than the latest period). If none is provided we will use the last period end as the evaluation date. The period resolution can be inferred from the first two consecutive periods, otherwise it must be provided as an integer. Metadata can be provided to add additional information to the cells. Field names will be inferred from the column names.

Parameters:
  • df – DataFrame to convert.

  • evaluation_date – Evaluation date for the static values. This is typically a placeholder date that is greater than the latest period in the triangle.

  • period_resolution – Period resolution in months. If None, this is inferred from the first consecutive period dates.

  • metadata – Metadata associated with the triangle.

static from_wide_csv()

Convert a wide-format CSV to a Triangle.

For more details on wide-format CSVs/tables, see wide_data_frame_to_triangle (which this function is a thin wrapper for).

Parameters:
  • file_or_fname – Name of the CSV file or a handle to a file object.

  • field_cols – Names of the columns that should be interpreted as fields.

  • detail_cols – Names of the columns that should be interpreted as metadata details. At least one of field_cols or detail_cols must be supplied.

  • loss_detail_cols – Names of the detail columns that should be interpreted as metadata loss details, rather than standard metadata details. By default, nothing is assumed to be a loss detail.

  • metadata – Default metadata to apply to every cell in the Triangle (can be overridden by detail_cols).

  • collapse_fields – A list of fields to collapse to a single value, rather than loading as an array with multiple values. This typically applies to earned_premium when multiple scenarios are being loaded.

  • **kwargs – Extra arguments to pd.read_csv

static from_wide_data_frame()

Convert a wide-format pd.DataFrame to a Triangle.

A wide-format DataFrame requires the following columns to be present: period_start, period_end, and evaluation_date. When the column ‘prev_evaluation_date’ is present, a triangle with incremental cells is generated. Otherwise, all triangle cells are cumulative.

Each row of the DataFrame represents a single Cell of the Triangle. Any columns besides the three required columns are interpreted as either fields (i.e., paid_loss, reported_loss) or metadata (i.e., per_occurrence_limit, currency, program_name).

This function doesn’t make any assumptions about which columns are fields and which are metadata based on their names. Instead, at least one of detail_cols or field_cols must be supplied to the function. If only one of those arguments is supplied, all other columns are assumed to belong to the other argument.

The metadata argument can be used to supply common metadata that may not be directly present in the DataFrame. For example, every Cell in the Triangle could be accident-basis, gross of reinsurance, including DCC. This could be supplied by a single Metadata object in the function call instead of adding several constant columns to the DataFrame.

Parameters:
  • df – Pandas DataFrame to convert to a Triangle.

  • field_cols – Names of the columns that should be interpreted as fields.

  • detail_cols – Names of the columns that should be interpreted as metadata details. At least one of field_cols or detail_cols must be supplied.

  • loss_detail_cols – Names of the detail columns that should be interpreted as metadata loss details, rather than standard metadata details. By default, nothing is assumed to be a loss detail.

  • metadata – Default metadata to apply to every cell in the Triangle (can be overridden by detail_cols).

  • collapse_fields – A list of fields to collapse to a single value, rather than loading as an array with multiple values. This typically applies to earned_premium when multiple scenarios are being loaded.

property has_consistent_currency: bool

Does every cell in the triangle use the same currency?

property has_consistent_risk_basis: bool

Does every cell in the triangle use the same risk basis?

property has_consistent_values_shapes: bool

Does every field have the same shape in each cell?

property is_disjoint: bool

Is the triangle disjoint?

A triangle is disjoint if there is no overlap between any pair of experience periods.

property is_empty: bool

Is the triangle empty?

property is_incremental: bool

Is the traingle incremental?

property is_multi_slice: bool

Does this triangle have multiple slices?

is_regular(dev_lag_unit='month') bool

Is the triangle regular?

A triangle is regular if it is semi-regular and the interval between consecutive development lags is always a constant.

property is_right_edge_ragged: bool

Returns True if any slice’s right edge encompasses different evaluation dates

is_semi_regular(dev_lag_unit='month') bool

Is the triangle semi-regular?

A triangle is semi-regular if it is disjoint and every experience period has the same duration.

property is_slicewise_disjoint: bool

Returns True if each triangle slice is disjoint.

make_right_diagonal(evaluation_dates, include_historic=False) Triangle

Create a new Triangle with one or more diagonals to the right of existing data.

make_right_triangle(dev_lags=None, dev_lag_unit='month') Triangle

Create the lower-right complement of a triangle.

merge(tri2: Triangle, join_type: str = 'full', on: list[str] | None = None) Triangle

Merge cells of two triangles, if coordinates overlap then prioritize right cell values.

All cells from tri1 and tri2 are preserved by this merge. If two cells overlap by index, (period_start, period_end, evaluation_date, metadata), then values from tri2 take precedence.

Merge is a higher-level operation that returns a Triangle of merged cells. For a lower-level implementation that returns a list of pairs of matched cells, see join.

merge is different from coalesce in that it combines the union of fields in cells at the same coordinates, where coalesce only keeps the fields and values from the cell with precedence.

Parameters:
  • tri1 – The lower-precedence, left triangle to merge.

  • tri2 – The higher-precedence, right triangle to merge.

  • join_type – The type of relational join to perform. For a list of all join types and their descriptions, see the documentation for join.

  • on – which metadata attributes and detail keys to join on when merging cell values. Default behavior is to consider all metadata attributes when merging cells.

Returns:

A triangle with the merged cells from the two triangles.

property metadata: list[Metadata]

A sorted list of all unique metadata in the Triangle.

property metadata_differences: list[Metadata]

A list of all unique metadata in the Triangle, with metadata attributes that are common to all Cells in the Triangle removed.

property num_samples: int

The number of samples in a Triangle of stochastic predictions. If the triangle has only observed data, num_samples is 1. If different cells or different fields have different values of num_samples, an error is raised.

period_merge(tri2: Triangle[Cell], suffix: str | None = None) Triangle[Cell]

Add period-level values of tri2 to tri1 cells. tri2 must have a single cell per period index.

All cells from tri1 are preserved by this merge. If there is a matching cell in tri2 by index (period_start, period_end, metadata), then values from tri2 take precedence. There must be only one cell in tri2 per index.

Parameters:
  • tri1 – First triangle in the merge.

  • tri2 – Second triangle in the merge.

  • suffix – If present, then every field in tri2 will have the suffix appended to the name of the field after the merge to avoid name conflicts. If None, then no suffix will be appended and the values in tri2 will overwrite the values in tri1.

property period_resolution: int

The resolution of the periods in the triangle.

property period_rows

Group by experience period and return an iterator over ‘rows’.

property periods: list[tuple[date, date]]

A sorted list of unique experience periods (as 2-tuples of start and end dates).

plot_data_completeness() Figure

Plot the coordinates of each cell in the Triangle along with metric coverage information.

Returns:

A scatterplot where each dot is a cell, the x-axis is development lags, the y-axis is experience periods, and the color is the number of distinct metrics in the cell.

plot_right_edge() plt.Figure | None

Plot the right edge of the triangle.

Returns:

A plot with historical earned premium bars and lines for historical paid and reported losses.

remove_static_details() Triangle

Removes any metadata details and loss_details that are common to all cells in the triangle.

replace(**definitions: Callable[[Cell], Any] | Any) Triangle

Replace cell member variables with a constant or via a function.

Parameters:

**definitions

New variable definitions, which must be one of period_start, period_end, evaluation_date or values. Definition values can either be constants or functions of the cell itself. For example,

triangle.replace(values=dict(reported_loss=1) triangle.replace(values=lambda cell: dict(reported_loss = cell[“paid_loss”]))

property right_edge

Create a Triangle with only the most recent observation for each period within each triangle slice.

Note that right_edge doesn’t guarantee that every cell will have the same evaluation date!

select(keys: list[str]) Triangle

Retain only the designated keys in values.

property slice_period_rows

Group by slice and experience period and return an iterator over ‘slice-rows’.

split(detail_keys: list[str]) dict[Any, Triangle]

Turn a Triangle into a dictionary of Triangles grouped by specified detail keys.

summarize(summary_fns: dict[str, Callable] | None = None, summarize_premium: bool = True) Triangle

Aggregate a Triangle across metadata.

For example, given a triangle with state and coverage-level detail, this would generate a triangle where all cells with the same coordinates are merged, and any metadata that varies over the triangle would be dropped.

Parameters:
  • triangle – The single triangle to summarize.

  • summary_fns – A dictionary of functions to use to summarize each field in the triangle. If None, a default set of functions is supplied. If specified, the dictionary is added to the default set of summary functions, which makes it possible to easily add functions for custom fields without affecting defaults.

  • summarize_premium – Whether to summarize the premium field. If False, the premium field will not be summed accross cells, but will be copied from the first matching cell in the triangle.

Returns:

A summarized triangle with a single cell for each unique combination of coordinates.

thin(num_samples: int, seed: int = None) Triangle

‘Thin out’ a triangle by replacing all array-typed values with a random subset of values. For example, given a triangle pred_tri with 10,000 samples per value, thin(pred_tri, 500) will return a triangle with 500 samples per value.

The thinning process takes the same random subset of samples from each value and preserves the relative order of the subsamples, so that correlations between values (both within and across cells) are preserved.

Parameters:
  • triangle – The triangle to thin.

  • num_samples – The number of samples of each array-valued value to return.

  • seed – The seed of the random number generator.

Returns:

A copy of the triangle with num_samples random samples.

to_array_data_frame(field: str)

Convert a Triangle object to a DataFrame in a triangular array format.

Parameters:
  • triangle – A single-sliced Triangle object.

  • field – Field name.

to_binary(filename: str, compress: bool = False) None

Convert a Bermuda triangle to a binary file format.

Parameters:
  • triangle – The Bermuda triangle to save out.

  • filename – The filename to save the triangle to.

  • compress – Whether to compress the file.

to_chain_ladder() chainladder.core.triangle.Triangle

Convert a Triangle to a chainladder Triangle object.

Parameters:

triangle (Triangle) – The Bermuda Triangle to convert.

Returns:

The chainladder Triangle object.

Return type:

chainladder.core.triangle.Triangle

to_cumulative() Triangle[CumulativeCell]

Convert a Triangle from incremental to cumulative basis.

to_data_frame(dev_lag_unit='month')

Convert a triangle set to a Pandas dataframe.

to_incremental() Triangle[IncrementalCell]

Convert a Triangle from cumulative to incremental basis.

to_json()

Convert a triangle to JSON.

Parameters:
  • tri – A triangle to convert to a JSON representation.

  • file_or_fname – A filename, a file handle, or None.

Returns:

If file_or_fname is None, then a string with the JSON representation of the triangle is returned. Otherwise, the JSON representation is written to the provided file and None is returned.

to_long_csv(filename: str) None

Convert a Triangle to a long-format CSV file.

See long_data_frame_to_triangle for details on the long format.

Parameters:
  • tri – Triangle to convert.

  • filename – Name of CSV file to create.

to_long_data_frame() DataFrame

Convert a Triangle to a long-format Pandas DataFrame.

See long_data_frame_to_triangle for details on the long format.

Parameters:

tri – Triangle to convert.

to_right_edge_data_frame() DataFrame

Convert a Triangle object to a DataFrame displaying values on the right edge of the triangle. The resulting dataframe will show the ‘period’, ‘evaluation_date’, and cell values for the right edge of the triangle.

Parameters:

triangle – A single-sliced Triangle object.

to_wide_csv(filename: str) None

Convert a Triangle to a wide-format CSV file.

See wide_data_frame_to_triangle for details on the wide format.

Parameters:
  • tri – Triangle to convert.

  • filename – Name of CSV file to create.

to_wide_data_frame() DataFrame

Convert a Triangle to a wide-format Pandas DataFrame.

See wide_data_frame_to_triangle for details on the wide format.

Parameters:

tri – Triangle to convert.

class bermuda.triangle.TriangleSlice(cells: Sequence[Cell])