Skip to main content

tlf-data-cleaning

Data extraction, transformation, normalization, deduplication, and quality-check pipelines for the TLF ecosystem — the tlf-data-cleaning package described in the TLF-Data-Manager README, built out as a real, installable, tested package.

It solves a concrete problem: government census reports (Bangladesh BBS, Pakistan PBS, etc.) are published as PDFs, not clean CSVs. This package extracts the raw tables out of those PDFs and runs them through a composable set of cleaning rules to produce the canonical schema that tlf-census-stats expects — without hardcoding any of that cleaning logic inside the stats package itself.

Install

pip install -e .
# or, for running the test suite too:
pip install -e ".[dev]"

Modules

Module Responsibility
extract.py PDFTableExtractor — pulls raw tables out of a PDF, no cleaning applied.
rules.py Composable CleaningRule steps: rename, strip whitespace, coerce numeric, dedupe, drop/fill missing, drop-by-predicate.
pipeline.py CleaningPipeline — chains rules together, optionally starting from a PDF, and can export straight to CSV.
quality.py QualityReport — missing values, duplicate rows, negative-value checks, summary snapshot.

Quick example: PDF → clean CSV

from tlf_data_cleaning import (
    CleaningPipeline, RenameColumns, StripWhitespace, CoerceNumeric, DropDuplicates,
)

pipeline = CleaningPipeline([
    RenameColumns({"Division": "region", "District": "subregion",
                   "Total Population": "total_population", "Male": "male",
                   "Female": "female", "Households": "households",
                   "Literacy Rate": "literacy_rate"}),
    StripWhitespace(columns=["region", "subregion"]),
    CoerceNumeric(["total_population", "male", "female", "households", "literacy_rate"]),
    DropDuplicates(subset=["region", "subregion"]),
])

clean_df = pipeline.run_from_pdf("bbs_district_report.pdf", page=12)
print(pipeline.quality_report().summary())

pipeline.run_and_export(clean_df, "data/sample/bangladesh_census_2022.csv")

Canonical schema

tlf-census-stats's CensusLoader expects data in this shape (see its country_profiles.py for exact per-country column aliases):

Column Required? Notes
region Yes e.g. Division/Province/State
subregion Yes e.g. District
total_population Yes
male Yes
female Yes
households Yes
urban_population Optional
rural_population Optional
literacy_rate Optional
avg_household_size Optional
third_gender Optional A country's non-binary census category (e.g. Bangladesh's "Hijra"). Not every country publishes this.

This package is the upstream step for two of the three ways data reaches tlf-census-stats — it turns a raw government PDF into a CSV in this same shape.

Three ways to get data into tlf-census-stats

1. Already-clean CSV/Excel/JSON — skip this package entirely

If your source is already a clean spreadsheet/CSV/JSON in (or close to) the canonical shape above, just hand it straight to CensusLoader — this package isn't needed at all:

from tlf_census_stats import CensusLoader
df = CensusLoader("already_clean_bangladesh_census.csv", country="bangladesh").load()

2. Flat-country PDF (e.g. Bangladesh, Pakistan) — this package handles the whole thing

Most countries' census PDFs are a flat table per page — extract, clean, and hand off directly:

from tlf_data_cleaning import (
    CleaningPipeline, RenameColumns, StripWhitespace, CoerceNumeric, DropDuplicates,
)
from tlf_census_stats import CensusLoader, StatsReporter

# 1. PDF -> clean CSV (this package)
pipeline = CleaningPipeline([
    RenameColumns({"Division": "region", "District": "subregion",
                   "Total Population": "total_population", "Male": "male",
                   "Female": "female", "Households": "households",
                   "Literacy Rate": "literacy_rate"}),
    StripWhitespace(columns=["region", "subregion"]),
    CoerceNumeric(["total_population", "male", "female", "households", "literacy_rate"]),
    DropDuplicates(subset=["region", "subregion"]),
])
pipeline.run_from_pdf_and_export(
    "bbs_district_report.pdf", page=12,
    output_path="data/sample/bangladesh_census_2022.csv",
)

# 2. clean CSV -> stats report (tlf-census-stats)
reporter = StatsReporter("data/sample/bangladesh_census_2022.csv", country="bangladesh")
reporter.run()

3. India's hierarchical PDF layout — extract here, transform in tlf-census-stats

India's census PDF has a nested INDIA → STATE → DISTRICT → SUB-DISTRICT structure that a generic CleaningPipeline of rename/strip/coerce rules can't reshape — that's what tlf-census-stats's IndiaCensusTransformer is specifically for. This package only does the raw extraction step; the reshaping happens on the other side:

from tlf_data_cleaning import PDFTableExtractor
from tlf_census_stats import IndiaCensusTransformer, CensusLoader, StatsReporter

# 1. Extract raw tables (this package) — no cleaning/reshaping applied
extractor = PDFTableExtractor("india_2011.pdf")
tables = extractor.extract_pages(range(1, 2226), known_header=IndiaCensusTransformer.EXPECTED_HEADER)

# 2. Reshape the hierarchical rows into canonical region/subregion rows (tlf-census-stats)
df = IndiaCensusTransformer().transform(tables)
df.to_csv("data/sample/india_from_pdf.csv", index=False)

# 3. Analyze (tlf-census-stats)
reporter = StatsReporter("data/sample/india_from_pdf.csv", country="india")
reporter.run()

Column names produced by workflow 2's pipeline just need to match the canonical schema table above for a given country's profile — workflow 3 doesn't need column renaming at all, since IndiaCensusTransformer already outputs canonical column names directly.

Notes on real government PDFs

  • pdfplumber's table detection works well on ruled/gridded tables (like the BBS district reports) but can miss tables with no visible borders — pass table_settings to extract_page/extract_all to tune detection (see pdfplumber's docs for vertical_strategy / horizontal_strategy options) if a specific report doesn't extract cleanly.
  • Multi-line headers or footnote rows sometimes get pulled in as data rows — inspect extractor.extract_page(n) output before wiring it into a CleaningPipeline, and add a DropRowsWhere rule to filter out any non-data rows if needed.

Tests

python -m pytest tests/ -v

tests/fixtures/generate_fixture.py builds the sample PDF used by the test suite — a small table with thousands separators, stray whitespace, and a duplicate row, mimicking real BBS/PBS-style reports. Regenerate it with:

python tests/fixtures/generate_fixture.py

Release files for tlf-data-cleaning 0.1.0

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

Source distribution (sdist)

Source distribution for tlf-data-cleaning 0.1.0
File Size Uploaded
tlf_data_cleaning-0.1.0.tar.gz 16.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tlf-data-cleaning 0.1.0
File Interpreter ABI Platform
tlf_data_cleaning-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.3 kB

Release files / tlf_data_cleaning-0.1.0.tar.gz

Download URL tlf_data_cleaning-0.1.0.tar.gz
Size 16.1 kB
Tags Source
SHA-256 checksum
How to use checksums
03b8421e9bfa686c44467eaf9c11ed9f14a8456120b2c24df8f7c71fdbf23ab3
BLAKE2b-256 checksum
How to use checksums
e5810fdc49b208facdc0d1d0abeec4b38095d01a3a5885cae39b482159bd64bd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release files / tlf_data_cleaning-0.1.0-py3-none-any.whl

Download URL tlf_data_cleaning-0.1.0-py3-none-any.whl
Size 11.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2ef925e2a28beb69816a0480399c5358a000757508a8f9390989ee11fd06b915
BLAKE2b-256 checksum
How to use checksums
23f3b9a1b24e56031d992b0120898a24a83872fce93cce870ac70129d3879ce4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release history Release notifications | RSS feed

0.1.2

2 release files

0.1.1

2 release files

This release

0.1.0 This release

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