Better
This commit is contained in:
parent
ca771a7edf
commit
d7f844d566
12 changed files with 198 additions and 251 deletions
|
|
@ -56,6 +56,22 @@ DYNAMIC_FILTER_ALL_GROUPS = {"Public Transport", "Leisure", "Health"}
|
|||
DYNAMIC_FILTER_COUNT_THRESHOLD_GROUPS = {"Groceries"}
|
||||
DYNAMIC_FILTER_EXCLUDED_CATEGORIES = {"Park"}
|
||||
|
||||
# Combined "nearest of any rail mode" distance: the distance to the closest of a
|
||||
# Rail station, Tube station, DLR station, or Tram & Metro stop. Materialized as
|
||||
# its own real column so the server loads it like any other per-category
|
||||
# distance. min_distance_per_postcode already supports multi-category groups, so
|
||||
# this is a genuine nearest-of-the-union query (identical to the per-mode
|
||||
# minimum). Distance only: a combined "within Xkm" count is not meaningful, so
|
||||
# it is intentionally omitted from the count groups.
|
||||
COMBINED_STATION_GROUP_KEY = "poi_any_station"
|
||||
COMBINED_STATION_DISPLAY_NAME = "Any station"
|
||||
COMBINED_STATION_SOURCE_CATEGORIES = [
|
||||
"Rail station",
|
||||
"Tube station",
|
||||
"DLR station",
|
||||
"Tram & Metro stop",
|
||||
]
|
||||
|
||||
|
||||
def _poi_category_slug(category: str) -> str:
|
||||
ascii_text = (
|
||||
|
|
@ -227,10 +243,21 @@ def main():
|
|||
dynamic_counts_5km = count_pois_per_postcode(
|
||||
postcodes, pois, groups=poi_category_groups, radius_km=5
|
||||
)
|
||||
# Distances additionally include the combined "Any station" group (nearest of
|
||||
# any rail mode). It is distance-only, so it is added here but not to the
|
||||
# 2km/5km count groups above.
|
||||
distance_groups = {
|
||||
**poi_category_groups,
|
||||
COMBINED_STATION_GROUP_KEY: COMBINED_STATION_SOURCE_CATEGORIES,
|
||||
}
|
||||
distance_display_names = {
|
||||
**poi_display_names,
|
||||
COMBINED_STATION_GROUP_KEY: COMBINED_STATION_DISPLAY_NAME,
|
||||
}
|
||||
dynamic_distances = min_distance_per_postcode(
|
||||
postcodes, pois, groups=poi_category_groups
|
||||
postcodes, pois, groups=distance_groups
|
||||
)
|
||||
dynamic_renames = _dynamic_poi_metric_renames(poi_display_names)
|
||||
dynamic_renames = _dynamic_poi_metric_renames(distance_display_names)
|
||||
dynamic_counts_2km = dynamic_counts_2km.rename(
|
||||
{k: v for k, v in dynamic_renames.items() if k in dynamic_counts_2km.columns}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import polars as pl
|
||||
|
||||
from pipeline.transform.poi_proximity import (
|
||||
COMBINED_STATION_DISPLAY_NAME,
|
||||
COMBINED_STATION_GROUP_KEY,
|
||||
COMBINED_STATION_SOURCE_CATEGORIES,
|
||||
GREENSPACE_PARK_FUNCTIONS,
|
||||
POI_GROUPS_2KM,
|
||||
_build_poi_category_groups,
|
||||
|
|
@ -8,7 +11,7 @@ from pipeline.transform.poi_proximity import (
|
|||
_greenspace_count_frame,
|
||||
_groceries_categories,
|
||||
)
|
||||
from pipeline.utils.poi_counts import count_pois_per_postcode
|
||||
from pipeline.utils.poi_counts import count_pois_per_postcode, min_distance_per_postcode
|
||||
|
||||
|
||||
def test_groceries_2km_counts_geolytix_brand_categories() -> None:
|
||||
|
|
@ -84,6 +87,42 @@ def test_dynamic_poi_groups_include_requested_categories_only() -> None:
|
|||
assert "poi_school" not in groups
|
||||
|
||||
|
||||
def test_combined_station_distance_is_nearest_of_any_rail_mode() -> None:
|
||||
"""The combined "Any station" distance is the nearest of Rail/Tube/DLR/Tram,
|
||||
materialized as its own column so the server loads it directly (no runtime
|
||||
synthesis). A far rail station and a near DLR stop: the combined distance
|
||||
must follow the DLR stop."""
|
||||
postcodes = pl.DataFrame(
|
||||
{"postcode": ["E14 5AB"], "lat": [51.5054], "lon": [-0.0235]}
|
||||
)
|
||||
pois = pl.DataFrame(
|
||||
{
|
||||
"category": ["Rail station", "DLR station"],
|
||||
"group": ["Public Transport", "Public Transport"],
|
||||
"lat": [51.6000, 51.5055],
|
||||
"lng": [-0.2000, -0.0236],
|
||||
}
|
||||
)
|
||||
|
||||
distance_groups = {
|
||||
"poi_rail_station": ["Rail station"],
|
||||
COMBINED_STATION_GROUP_KEY: COMBINED_STATION_SOURCE_CATEGORIES,
|
||||
}
|
||||
result = min_distance_per_postcode(postcodes, pois, groups=distance_groups)
|
||||
renames = _dynamic_poi_metric_renames(
|
||||
{COMBINED_STATION_GROUP_KEY: COMBINED_STATION_DISPLAY_NAME}
|
||||
)
|
||||
result = result.rename({k: v for k, v in renames.items() if k in result.columns})
|
||||
|
||||
combined = result["Distance to nearest amenity (Any station) (km)"][0]
|
||||
rail_only = result["poi_rail_station_nearest_km"][0]
|
||||
# The near DLR stop is within a few hundred metres; the only rail station is
|
||||
# kilometres away. The combined distance must follow the DLR stop.
|
||||
assert combined < 0.2
|
||||
assert rail_only > 5.0
|
||||
assert combined < rail_only
|
||||
|
||||
|
||||
def test_dynamic_poi_metric_renames_support_park_count_options() -> None:
|
||||
assert _dynamic_poi_metric_renames({"parks": "Park"}) == {
|
||||
"parks_nearest_km": "Distance to nearest amenity (Park) (km)",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue