bolster.data_sources.nisra.deaths

NISRA Weekly Death Registrations Data Source.

Provides access to weekly death registration statistics for Northern Ireland with breakdowns by: - Demographics (age, sex) - Geography (Local Government Districts) - Place of death (hospital, home, care home, etc.)

Data is based on registration date, not death occurrence date. Most deaths are registered within 5 days in Northern Ireland.

Data Source:

Mother Page: https://www.nisra.gov.uk/statistics/death-statistics/weekly-death-registrations-northern-ireland

This page lists all weekly death registration publications in reverse chronological order (newest first). The module automatically scrapes this page to find the current year’s publication (e.g., “Weekly Death Registrations in Northern Ireland, 2025”), then downloads the latest weekly Excel file from that publication’s detail page.

The weekly files are cumulative, containing all weeks for the year to date. This ensures the module always retrieves the most recent data without hardcoding week numbers or dates.

Update Frequency: Weekly (published Fridays for week ending previous Friday) Geographic Coverage: Northern Ireland

Example

>>> from bolster.data_sources.nisra import deaths
>>> # Get latest demographics breakdown
>>> df = deaths.get_latest_deaths(dimension='demographics')
>>> sorted(df.columns.tolist())
['age_range', 'deaths', 'sex', 'week_ending']
>>> len(df) > 0
True

Attributes

logger

WEEKLY_DEATHS_LANDING_PAGE

WEEKLY_DEATHS_BASE_URL

HISTORICAL_DEATHS_URL

DimensionType

Functions

get_latest_weekly_deaths_url()

Scrape NISRA mother page to find the latest weekly deaths file.

parse_deaths_totals(file_path)

Parse weekly totals with COVID-19, flu/pneumonia, and excess deaths from weekly deaths file.

parse_deaths_demographics(file_path)

Parse demographics dimension (age, sex) from weekly deaths file.

parse_deaths_geography(file_path)

Parse geography dimension (Local Government Districts) from weekly deaths file.

parse_deaths_place(file_path)

Parse place of death dimension from weekly deaths file.

parse_deaths_file(file_path[, dimension])

Parse weekly deaths file for one or all dimensions.

get_latest_deaths([dimension, force_refresh])

Get the latest weekly deaths data.

get_historical_deaths([years, force_refresh, ...])

Get historical weekly deaths data (2011-2024).

get_combined_deaths([years, include_current_year, ...])

Get combined historical and current year deaths data.

validate_deaths_data(df)

Validate NISRA deaths data integrity.

Module Contents

bolster.data_sources.nisra.deaths.logger[source]
bolster.data_sources.nisra.deaths.WEEKLY_DEATHS_LANDING_PAGE = 'https://www.nisra.gov.uk/publications/weekly-death-registrations-northern-ireland-{year}'[source]
bolster.data_sources.nisra.deaths.WEEKLY_DEATHS_BASE_URL = 'https://www.nisra.gov.uk/statistics/death-statistics/weekly-death-registrations-northern-ireland'[source]
bolster.data_sources.nisra.deaths.HISTORICAL_DEATHS_URL = 'https://www.nisra.gov.uk/publications/historical-final-weekly-deaths-data'[source]
bolster.data_sources.nisra.deaths.DimensionType[source]
bolster.data_sources.nisra.deaths.get_latest_weekly_deaths_url()[source]

Scrape NISRA mother page to find the latest weekly deaths file.

Navigates the publication structure: 1. Scrapes mother page for current year publication 2. Follows link to publication detail page 3. Finds latest weekly Excel file 4. Extracts and validates week ending date

Returns:

URL of the latest weekly deaths Excel file

Raises:

NISRADataNotFoundError – If no file found

Return type:

str

bolster.data_sources.nisra.deaths.parse_deaths_totals(file_path)[source]

Parse weekly totals with COVID-19, flu/pneumonia, and excess deaths from weekly deaths file.

Extracts Table 1a and creates a flat table with columns:

  • week_ending: Friday of the reporting week

  • week_number: Week number in the year

  • observed_deaths: Total deaths registered in the week

  • deaths_same_week_2024: Deaths in corresponding week in 2024

  • expected_deaths_5yr: Average deaths over previous 5 years (2020-2024)

  • expected_deaths_ons: Average deaths using ONS methodology (2019, 2021-2024)

  • excess_deaths_5yr: Observed minus expected (5yr method)

  • expected_deaths_current: Expected deaths using current methodology

  • excess_deaths_current: Observed minus expected (current method)

  • flu_pneumonia_deaths: Deaths mentioning flu or pneumonia

  • covid_deaths: Deaths mentioning COVID-19

Parameters:

file_path (str | pathlib.Path) – Path to the weekly deaths Excel file

Returns:

DataFrame with weekly totals and disease-specific deaths

Raises:

NISRAValidationError – If data validation fails

Return type:

pandas.DataFrame

bolster.data_sources.nisra.deaths.parse_deaths_demographics(file_path)[source]

Parse demographics dimension (age, sex) from weekly deaths file.

Extracts Table 2 and creates a flat table with columns:

  • week_ending: Friday of the reporting week

  • sex: Total, Male, or Female

  • age_range: All, 0-14, 15-44, 45-64, 65-74, 75-84, 85+

  • deaths: Count of deaths

Parameters:

file_path (str | pathlib.Path) – Path to the weekly deaths Excel file

Returns:

DataFrame with demographics breakdown

Raises:

NISRAValidationError – If data validation fails

Return type:

pandas.DataFrame

bolster.data_sources.nisra.deaths.parse_deaths_geography(file_path)[source]

Parse geography dimension (Local Government Districts) from weekly deaths file.

Extracts Table 3 and creates a flat table with columns:

  • week_ending: Friday of the reporting week

  • lgd: Local Government District name

  • deaths: Count of deaths

Parameters:

file_path (str | pathlib.Path) – Path to the weekly deaths Excel file

Returns:

DataFrame with geography breakdown

Raises:

NISRAValidationError – If data validation fails

Return type:

pandas.DataFrame

bolster.data_sources.nisra.deaths.parse_deaths_place(file_path)[source]

Parse place of death dimension from weekly deaths file.

Extracts Table 4 and creates a flat table with columns:

  • week_ending: Friday of the reporting week

  • place_of_death: Hospital, Care/Nursing Home, Hospice, Home, Other

  • deaths: Count of deaths

Parameters:

file_path (str | pathlib.Path) – Path to the weekly deaths Excel file

Returns:

DataFrame with place of death breakdown

Raises:

NISRAValidationError – If data validation fails

Return type:

pandas.DataFrame

bolster.data_sources.nisra.deaths.parse_deaths_file(file_path, dimension='all')[source]

Parse weekly deaths file for one or all dimensions.

Parameters:
  • file_path (str | pathlib.Path) – Path to the weekly deaths Excel file

  • dimension (DimensionType) – Which dimension(s) to parse: - ‘totals’: Weekly totals with COVID, flu/pneumonia, excess deaths - ‘demographics’: Age and sex breakdown - ‘geography’: Local Government Districts - ‘place’: Place of death - ‘all’: All dimensions (returns dict)

Returns:

DataFrame for single dimension, or dict of DataFrames for ‘all’

Return type:

pandas.DataFrame | dict[str, pandas.DataFrame]

Example

>>> url = get_latest_weekly_deaths_url()
>>> path = download_file(url, cache_ttl_hours=24*7)
>>> data = parse_deaths_file(path, dimension='all')
>>> sorted(data.keys())
['demographics', 'geography', 'place', 'totals']
bolster.data_sources.nisra.deaths.get_latest_deaths(dimension='all', force_refresh=False)[source]

Get the latest weekly deaths data.

Parameters:
  • dimension (DimensionType) – Which dimension(s) to retrieve

  • force_refresh (bool) – Force re-download even if cached

Returns:

DataFrame or dict of DataFrames depending on dimension

Return type:

pandas.DataFrame | dict[str, pandas.DataFrame]

Example

>>> df = get_latest_deaths(dimension='demographics')
>>> sorted(df.columns.tolist())
['age_range', 'deaths', 'sex', 'week_ending']
>>> len(df) > 0
True
bolster.data_sources.nisra.deaths.get_historical_deaths(years=None, force_refresh=False, include_age_breakdowns=False)[source]

Get historical weekly deaths data (2011-2024).

Downloads and parses the NISRA historical weekly deaths file which contains final (not provisional) data for multiple years. Includes total deaths, respiratory deaths, COVID-19 deaths, flu/pneumonia deaths, and age breakdowns.

Parameters:
  • years (list[int] | None) – List of years to include (default: all available years)

  • force_refresh (bool) – Force re-download even if cached

  • include_age_breakdowns (bool) – If True, returns dict with ‘totals’ and ‘age_breakdowns’ DataFrames If False (default), returns only totals DataFrame

Returns:

DataFrame with columns:

  • year: Year

  • week_number: Week number in year

  • week_ending: Friday of the reporting week

  • total_deaths: Total deaths registered in week

  • expected_deaths_5yr: Average deaths over previous 5 years

  • excess_deaths: Observed minus expected deaths

  • respiratory_deaths_involving: Deaths involving respiratory diseases

  • flu_pneumonia_deaths_involving: Deaths involving flu/pneumonia

  • covid_deaths_involving: Deaths involving COVID-19

  • covid_deaths_due_to: Deaths due to COVID-19 (underlying cause)

If include_age_breakdowns=True:

Dict with keys:

  • ’totals’: DataFrame as above

  • ’age_breakdowns’: DataFrame in long format with columns:

    • year: Year

    • week_ending: Friday of the reporting week

    • age_range: Age range label (e.g., ‘0-7 days’, ‘15-44’, ‘85+’)

    • deaths: Death count for this age range

Return type:

If include_age_breakdowns=False

Example

>>> # Get totals only
>>> df = get_historical_deaths()
>>> 'total_deaths' in df.columns
True
>>> # Get totals with age breakdowns
>>> data = get_historical_deaths(years=[2020, 2021], include_age_breakdowns=True)
>>> sorted(data.keys())
['age_breakdowns', 'totals']
>>> totals = data['totals']
>>> age_data = data['age_breakdowns']
>>> # Analyze age distribution
>>> age_summary = age_data.groupby('age_range')['deaths'].sum()
>>> len(age_summary) > 0
True
bolster.data_sources.nisra.deaths.get_combined_deaths(years=None, include_current_year=True, force_refresh=False)[source]

Get combined historical and current year deaths data.

Combines the historical deaths file (2011-2024) with the current year’s provisional data to give a complete time series including the most recent weeks.

Parameters:
  • years (list[int] | None) – List of years to include from historical data (default: last 5 years + current)

  • include_current_year (bool) – Include current year provisional data (default: True)

  • force_refresh (bool) – Force re-download of both historical and current files

Returns:

  • year: Year

  • week_number: Week number in year

  • week_ending: Friday of the reporting week

  • total_deaths: Total deaths registered in week

  • covid_deaths: COVID-19 deaths (from current year) or covid_deaths_involving (historical)

  • flu_pneumonia_deaths: Flu/pneumonia deaths

  • excess_deaths: Excess deaths (observed - expected)

  • data_source: ‘historical’ or ‘current’

Return type:

DataFrame with columns

Example

>>> df = get_combined_deaths(years=[2022, 2023, 2024])
>>> 'total_deaths' in df.columns
True
>>> 'data_source' in df.columns
True
bolster.data_sources.nisra.deaths.validate_deaths_data(df)[source]

Validate NISRA deaths data integrity.

Parameters:

df (pandas.DataFrame) – DataFrame from get_latest_deaths or parse_deaths_file

Returns:

True if validation passes, False otherwise

Return type:

bool