SPlit up
Some checks failed
CI / Check (push) Failing after 1m58s
Build and publish Docker image / build-and-push (push) Failing after 1m5s

This commit is contained in:
Andras Schmelczer 2026-06-12 21:51:37 +01:00
parent cf39ad754e
commit f59d01227b
91 changed files with 10370 additions and 7562 deletions

View file

@ -30,13 +30,31 @@ AREA_CODE_ALIASES = {
}
def _data_rows(df: pl.DataFrame) -> pl.DataFrame:
"""Rows below Table 1's header row.
The preamble length varies (title, optional "This worksheet contains..."
note, then the header row starting with "Time period"), so locate the
header by content instead of counting rows a fixed slice leaves the
header in the data whenever ONS adds or removes a note line.
"""
header_marker = (
pl.col("column_1").cast(pl.String).str.strip_chars().str.to_lowercase()
== "time period"
)
header_rows = df.with_row_index("_row").filter(header_marker)
if header_rows.is_empty():
raise ValueError("PIPR Table 1: no 'Time period' header row found")
return df.slice(int(header_rows["_row"][0]) + 1)
def _latest_rents_long(df: pl.DataFrame) -> pl.DataFrame:
# Table 1 layout: row 0 = title, row 1 = column headers, row 2+ = data.
# 40 columns in repeating blocks of 4 (index, monthly change, annual change,
# rental price) for each category. Rental price columns (0-indexed):
# Table 1 layout below the header: 40 columns in repeating blocks of 4
# (index, monthly change, annual change, rental price) for each category.
# Rental price columns (0-indexed):
# 7 = All categories, 11 = One bed, 15 = Two bed, 19 = Three bed,
# 23 = Four or more bed
df = df.slice(2) # Skip title and header rows
df = _data_rows(df)
df = df.select(
pl.col("column_1").alias("time_period"),