diff --git a/transform/sqlmesh_padelnomics/models/serving/location_profiles.sql b/transform/sqlmesh_padelnomics/models/serving/location_profiles.sql index 68f2197..0fd5b9a 100644 --- a/transform/sqlmesh_padelnomics/models/serving/location_profiles.sql +++ b/transform/sqlmesh_padelnomics/models/serving/location_profiles.sql @@ -5,15 +5,18 @@ -- -- Two scores per location: -- --- Padelnomics Market Score (Marktreife-Score v3, 0–100): +-- Padelnomics Market Score (Marktreife-Score v4, 0–100): -- "How mature/established is this padel market?" -- Only meaningful for locations matched to a dim_cities row (city_slug IS NOT NULL) -- with padel venues. 0 for all other locations. -- --- 40 pts supply development — log-scaled density (LN ceiling 20/100k) × count gate --- 25 pts demand evidence — occupancy when available; 40% density proxy otherwise +-- v4 changes: lower count gate (5→3), lower density ceiling (LN(21)→LN(11)), +-- better demand fallback (0.4→0.65 with 0.3 floor), economic context discrimination (200→25K). +-- +-- 40 pts supply development — log-scaled density (LN ceiling 10/100k) × count gate (3) +-- 25 pts demand evidence — occupancy when available; 65% density proxy + 0.3 floor otherwise -- 15 pts addressable market — log-scaled population, ceiling 1M --- 10 pts economic context — income PPS normalised to 200 ceiling +-- 10 pts economic context — income PPS normalised to 25,000 ceiling -- 10 pts data quality — completeness discount -- -- Padelnomics Opportunity Score (Marktpotenzial-Score v4, 0–100): @@ -146,34 +149,38 @@ market_scored AS ( WHEN population > 0 OR COALESCE(city_padel_venue_count, 0) > 0 THEN 0.5 ELSE 0.0 END AS data_confidence, - -- ── Market Score (Marktreife-Score v3) ────────────────────────────────── + -- ── Market Score (Marktreife-Score v4) ────────────────────────────────── -- 0 when no city match or no venues (city_padel_venue_count NULL or 0) CASE WHEN COALESCE(city_padel_venue_count, 0) > 0 THEN ROUND( -- Supply development (40 pts) + -- density ceiling 10/100k (LN(11)), count gate 3 venues 40.0 * LEAST(1.0, LN( COALESCE( CASE WHEN population > 0 THEN COALESCE(city_padel_venue_count, 0)::DOUBLE / population * 100000 ELSE 0 END - , 0) + 1) / LN(21)) - * LEAST(1.0, COALESCE(city_padel_venue_count, 0) / 5.0) + , 0) + 1) / LN(11)) + * LEAST(1.0, COALESCE(city_padel_venue_count, 0) / 3.0) -- Demand evidence (25 pts) + -- with occupancy: scale to 65% target. Without: 65% of supply proxy + 0.3 floor + -- (existence of venues IS evidence of demand) + 25.0 * CASE WHEN median_occupancy_rate IS NOT NULL THEN LEAST(1.0, median_occupancy_rate / 0.65) - ELSE 0.4 * LEAST(1.0, LN( + ELSE GREATEST(0.3, 0.65 * LEAST(1.0, LN( COALESCE( CASE WHEN population > 0 THEN COALESCE(city_padel_venue_count, 0)::DOUBLE / population * 100000 ELSE 0 END - , 0) + 1) / LN(21)) - * LEAST(1.0, COALESCE(city_padel_venue_count, 0) / 5.0) + , 0) + 1) / LN(11)) + * LEAST(1.0, COALESCE(city_padel_venue_count, 0) / 3.0)) END -- Addressable market (15 pts) + 15.0 * LEAST(1.0, LN(GREATEST(population, 1)) / LN(1000000)) -- Economic context (10 pts) - + 10.0 * LEAST(1.0, COALESCE(median_income_pps, 100) / 200.0) + -- ceiling 25,000 PPS discriminates between wealthy and poorer markets + + 10.0 * LEAST(1.0, COALESCE(median_income_pps, 15000) / 25000.0) -- Data quality (10 pts) + 10.0 * CASE WHEN population > 0 AND COALESCE(city_padel_venue_count, 0) > 0 THEN 1.0