bolster.data_sources.nisra.labour_market

NISRA Labour Market Statistics Module.

This module provides access to Northern Ireland Statistics and Research Agency (NISRA) Labour Force Survey (LFS) data.

The Labour Force Survey is a sample survey of households providing information on the labour force using internationally agreed concepts and definitions. It provides estimates of employment, unemployment, and economic inactivity.

Data is published quarterly covering 3-month rolling periods (e.g., “July to September 2025”). Some tables (particularly Local Government District breakdowns) are published annually only.

Data Source:

Mother Page: https://www.nisra.gov.uk/statistics/labour-market-and-social-welfare

This page lists all Labour Market and Social Welfare publications in reverse chronological order (newest first). The module automatically scrapes this page to find the latest “Quarterly Labour Force Survey Tables” publication, then downloads the Excel file from that publication’s detail page.

This ensures the module always retrieves the most recent data without hardcoding dates or quarters.

Update Frequency: Quarterly publications covering 3-month rolling periods are released approximately 6-8 weeks after the reference period ends. Labour Force Survey data is published four times per year with additional annual publications containing Local Government District breakdowns. Data is updated as part of NISRA’s regular labour market statistics programme following ONS Labour Force Survey methodology.

Architecture:
  • Automatically discovers latest quarterly LFS publication from NISRA mother page

  • Downloads quarterly Labour Force Survey Excel files

  • Parses multiple tables including:
    • Employment by age band and sex (Table 2.15)

    • Employment by industry sector (Table 2.17)

    • Employment by occupation (Table 2.18)

    • Economic inactivity (Table 2.21)

    • Unemployment rates (Table 2.22)

  • Separately handles annual Local Government District data (Table 1.16a) published in dedicated LGD tables file (not in quarterly publications)

  • Returns long-format DataFrames for flexibility

  • Uses standardized Excel parsing utilities from _base.py

Usage:
>>> from bolster.data_sources.nisra import labour_market
>>> # Get latest quarterly employment data
>>> df = labour_market.get_latest_employment()
>>> # Get economic inactivity data
>>> df = labour_market.get_latest_economic_inactivity()
>>> # Get all tables for a specific quarter
>>> data = labour_market.get_quarterly_data(year=2025, quarter="Jul-Sep")
>>> # Get annual employment by Local Government District
>>> lgd_df = labour_market.get_latest_employment_by_lgd()

Example

>>> from bolster.data_sources.nisra import labour_market
>>> emp_df = labour_market.get_latest_employment()
>>> 'age_group' in emp_df.columns
True
>>> lgd_df = labour_market.get_latest_employment_by_lgd()
>>> 'employment_rate' in lgd_df.columns
True

Author: Claude Code Date: 2025-12-21

Attributes

logger

LFS_CACHE_DIR

LFS_BASE_URL

Functions

download_quarterly_lfs(year, quarter[, force_refresh, ...])

Download Labour Force Survey quarterly tables Excel file.

parse_employment_by_age_sex(file_path)

Parse Table 2.15: Employment by Age Band and Sex.

parse_economic_inactivity(file_path)

Parse Table 2.21: Economically Inactive by Sex (Time Series).

get_latest_lfs_publication_url()

Find the latest Labour Force Survey quarterly tables publication.

get_latest_employment([force_refresh])

Get the latest quarterly employment data by age and sex.

get_latest_economic_inactivity([force_refresh])

Get the latest quarterly economic inactivity data.

get_quarterly_data(year, quarter[, tables, force_refresh])

Get Labour Force Survey data for a specific quarter.

get_latest_lgd_employment_url()

Get the URL of the latest LFS Local Government District tables publication.

parse_employment_by_lgd(file_path[, year])

Parse Table 1.16a: Employment by Local Government District (ages 16+).

get_latest_employment_by_lgd([force_refresh])

Get the latest Employment by Local Government District data.

validate_labour_market_data(df)

Validate labour market data integrity.

Module Contents

bolster.data_sources.nisra.labour_market.logger[source]
bolster.data_sources.nisra.labour_market.LFS_CACHE_DIR[source]
bolster.data_sources.nisra.labour_market.LFS_BASE_URL = 'https://www.nisra.gov.uk'[source]
bolster.data_sources.nisra.labour_market.download_quarterly_lfs(year, quarter, force_refresh=False, cache_ttl_days=90)[source]

Download Labour Force Survey quarterly tables Excel file.

Parameters:
  • year (int) – Year (e.g., 2025)

  • quarter (str) – Quarter string like “Jul-Sep”, “Jan-Mar”, etc.

  • force_refresh (bool) – If True, always download fresh data ignoring cache

  • cache_ttl_days (int) – Cache time-to-live in days (default: 90 days)

Returns:

Path to the downloaded Excel file

Raises:

NISRADataNotFoundError – If the file cannot be downloaded

Return type:

pathlib.Path

Example

>>> file_path = download_quarterly_lfs(2025, "Jul-Sep")
>>> file_path.exists()
True
bolster.data_sources.nisra.labour_market.parse_employment_by_age_sex(file_path)[source]

Parse Table 2.15: Employment by Age Band and Sex.

Extracts employment numbers and percentages broken down by age group and sex.

Parameters:

file_path (str | pathlib.Path) – Path to the quarterly LFS Excel file

Returns:

  • quarter_period: Quarter label (e.g., “July to September 2025”)

  • age_group: Age band (e.g., “16 to 19”, “20 to 24”, “25 to 29”, etc.)

  • sex: “Male”, “Female”, or “All Persons”

  • percentage: Percentage of employment in this age group (for this sex)

  • number: Absolute number employed (from Table 2.15b)

Return type:

DataFrame with columns

Example

>>> url, year, quarter = get_latest_lfs_publication_url()
>>> path = download_file(url, cache_ttl_hours=90*24)
>>> df = parse_employment_by_age_sex(path)
>>> 'age_group' in df.columns
True
bolster.data_sources.nisra.labour_market.parse_economic_inactivity(file_path)[source]

Parse Table 2.21: Economically Inactive by Sex (Time Series).

Extracts economic inactivity data broken down by sex with historical time series. Table 2.21 shows data for the same quarter (e.g., Jul-Sep) across multiple years (2012-2025).

Parameters:

file_path (str | pathlib.Path) – Path to the quarterly LFS Excel file

Returns:

  • time_period: Quarter label (e.g., “Jul to Sep 2025”)

  • sex: “Male”, “Female”, or “All Persons”

  • economically_inactive_number: Number of people economically inactive

  • economic_inactivity_rate: Percentage economically inactive

Return type:

DataFrame with columns

Note

Economically inactive persons are those not in employment and not seeking work (students, retired, caring for family, long-term sick/disabled, etc.).

This table provides historical time series for the same quarter across years, allowing year-over-year comparisons for the same seasonal period.

Example

>>> url, year, quarter = get_latest_lfs_publication_url()
>>> path = download_file(url, cache_ttl_hours=90*24)
>>> df = parse_economic_inactivity(path)
>>> 'economic_inactivity_rate' in df.columns
True
bolster.data_sources.nisra.labour_market.get_latest_lfs_publication_url()[source]

Find the latest Labour Force Survey quarterly tables publication.

Scrapes the NISRA Labour Market statistics mother page to find the most recent “Quarterly Labour Force Survey Tables” publication.

Returns:

Tuple of (excel_file_url, year, quarter) - excel_file_url: Full URL to the Excel file - year: Data year as string (e.g., “2025”) - quarter: Quarter string (e.g., “Jul-Sep”)

Raises:

NISRADataNotFoundError – If no publication found

Return type:

tuple[str, str, str]

Example

>>> url, year, quarter = get_latest_lfs_publication_url()
>>> url.startswith('https://')
True
bolster.data_sources.nisra.labour_market.get_latest_employment(force_refresh=False)[source]

Get the latest quarterly employment data by age and sex.

Automatically discovers and downloads the most recent quarterly LFS publication from the NISRA website.

Parameters:

force_refresh (bool) – If True, always download fresh data ignoring cache

Returns:

DataFrame with employment statistics by age group and sex

Return type:

pandas.DataFrame

Example

>>> df = get_latest_employment()
>>> 'age_group' in df.columns
True
>>> young_adults = df[df['age_group'] == '25 to 29']
>>> len(young_adults) >= 0
True
bolster.data_sources.nisra.labour_market.get_latest_economic_inactivity(force_refresh=False)[source]

Get the latest quarterly economic inactivity data.

Automatically discovers and downloads the most recent quarterly LFS publication from the NISRA website.

Parameters:

force_refresh (bool) – If True, always download fresh data ignoring cache

Returns:

DataFrame with economic inactivity statistics by sex

Return type:

pandas.DataFrame

Example

>>> df = get_latest_economic_inactivity()
>>> 'sex' in df.columns
True
bolster.data_sources.nisra.labour_market.get_quarterly_data(year, quarter, tables=None, force_refresh=False)[source]

Get Labour Force Survey data for a specific quarter.

Parameters:
  • year (int) – Year (e.g., 2025)

  • quarter (str) – Quarter string like “Jul-Sep”, “Jan-Mar”, etc.

  • tables (list[str] | None) – List of table names to parse (default: [‘employment’, ‘economic_inactivity’]) Options: ‘employment’, ‘economic_inactivity’

  • force_refresh (bool) – If True, always download fresh data ignoring cache

Returns:

  • ‘employment’: Employment by age and sex (Table 2.15)

  • ’economic_inactivity’: Economic inactivity data (Table 2.21)

Return type:

Dictionary mapping table names to DataFrames

Example

>>> data = get_quarterly_data(2025, "Jul-Sep")
>>> sorted(data.keys())
['economic_inactivity', 'employment']
>>> emp_df = data['employment']
>>> 'age_group' in emp_df.columns
True
bolster.data_sources.nisra.labour_market.get_latest_lgd_employment_url()[source]

Get the URL of the latest LFS Local Government District tables publication.

Uses known URL pattern to construct the file URL. The LGD tables are published annually but not listed on the main Labour Market page.

Returns:

Tuple of (excel_url, year)

Raises:

NISRADataNotFoundError – If unable to find the latest publication

Return type:

tuple[str, int]

Example

>>> url, year = get_latest_lgd_employment_url()
>>> url.startswith('https://')
True
bolster.data_sources.nisra.labour_market.parse_employment_by_lgd(file_path, year=None)[source]

Parse Table 1.16a: Employment by Local Government District (ages 16+).

Extracts employment statistics for all 11 Northern Ireland LGDs from the annual LFS LGD tables file.

Parameters:
  • file_path (str | pathlib.Path) – Path to the LFS LGD tables Excel file

  • year (int) – Year of the data (if not provided, will be extracted from sheet name)

Returns:

  • year: int

  • lgd: str (Local Government District name)

  • population_16plus: int (thousands)

  • economically_active: int (thousands)

  • in_employment: int (thousands)

  • full_time_employment: int (thousands)

  • part_time_employment: int (thousands)

  • economically_inactive: int (thousands)

  • economic_activity_rate: float (%)

  • employment_rate: float (%)

Return type:

DataFrame with columns

Example

>>> url, year = get_latest_lgd_employment_url()
>>> path = download_file(url, cache_ttl_hours=180*24)
>>> df = parse_employment_by_lgd(path, year=year)
>>> 'employment_rate' in df.columns
True
bolster.data_sources.nisra.labour_market.get_latest_employment_by_lgd(force_refresh=False)[source]

Get the latest Employment by Local Government District data.

Downloads and parses the most recent annual LFS LGD tables publication. Results are cached for 180 days unless force_refresh=True.

Parameters:

force_refresh (bool) – If True, bypass cache and download fresh data

Returns:

DataFrame with employment statistics for all 11 NI Local Government Districts

Return type:

pandas.DataFrame

Example

>>> df = get_latest_employment_by_lgd()
>>> 'employment_rate' in df.columns
True
>>> len(df) > 0
True
bolster.data_sources.nisra.labour_market.validate_labour_market_data(df)[source]

Validate labour market data integrity.

Parameters:

df (pandas.DataFrame) – DataFrame from labour market functions

Returns:

True if validation passes, False otherwise

Return type:

bool