feat(db): v_bucket_success_score view (success-driven mix #25)
This commit is contained in:
parent
8be539ddc6
commit
369b5a4706
1 changed files with 102 additions and 0 deletions
102
data/sql/86_v_bucket_success_score.sql
Normal file
102
data/sql/86_v_bucket_success_score.sql
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
-- 86_v_bucket_success_score.sql
|
||||
-- Context: Success-driven bucket ranking view for recommend_mix (issue #25).
|
||||
-- Per-(district × class × room_bucket) aggregates from domrf_kn_flats + domrf_kn_objects
|
||||
-- over the last 24 months, with Z-scores normalised per (district, class) group.
|
||||
-- Used in recommend_mix to bias recommendations toward buckets with high velocity + price.
|
||||
--
|
||||
-- Dependencies:
|
||||
-- domrf_kn_flats — total_area, rooms, price_per_m2, obj_id, region_cd, snapshot_date
|
||||
-- domrf_kn_objects — obj_id, district_name, obj_class, region_cd, snapshot_date
|
||||
-- domrf_kn_sale_graph — obj_id, report_month, contracted, snapshot_date
|
||||
--
|
||||
-- Deploy order: standalone, no prior migration needed.
|
||||
-- Idempotent: CREATE OR REPLACE VIEW.
|
||||
|
||||
BEGIN;
|
||||
|
||||
CREATE OR REPLACE VIEW v_bucket_success_score AS
|
||||
WITH
|
||||
-- Latest snapshot per object (both tables are time-series)
|
||||
latest_obj AS (
|
||||
SELECT DISTINCT ON (obj_id)
|
||||
obj_id, district_name, obj_class, region_cd
|
||||
FROM domrf_kn_objects
|
||||
WHERE district_name IS NOT NULL
|
||||
ORDER BY obj_id, snapshot_date DESC
|
||||
),
|
||||
|
||||
bucket_aggs AS (
|
||||
SELECT
|
||||
o.district_name,
|
||||
COALESCE(o.obj_class, 'Comfort') AS obj_class,
|
||||
CASE
|
||||
WHEN f.rooms = 0 OR f.total_area < 30 THEN 'Студии 15-30'
|
||||
WHEN f.total_area < 45 THEN '1-к 30-45'
|
||||
WHEN f.total_area < 60 THEN '2-к 45-60'
|
||||
WHEN f.total_area < 80 THEN '3-к 60-80'
|
||||
ELSE '80+ м²'
|
||||
END AS bucket,
|
||||
AVG(NULLIF(f.price_per_m2, 0)) AS avg_price_per_m2,
|
||||
AVG(NULLIF(f.total_area, 0)) AS avg_area_m2,
|
||||
COUNT(*) AS n_deals,
|
||||
-- Velocity proxy: avg monthly contracted units per object, over last 24 months
|
||||
AVG(
|
||||
(SELECT AVG(sg.contracted)
|
||||
FROM domrf_kn_sale_graph sg
|
||||
WHERE sg.obj_id = o.obj_id
|
||||
AND sg.report_month > NOW() - INTERVAL '24 months')
|
||||
) AS avg_velocity_per_month
|
||||
FROM domrf_kn_flats f
|
||||
JOIN latest_obj o ON o.obj_id = f.obj_id
|
||||
WHERE f.total_area BETWEEN 15 AND 200
|
||||
AND f.price_per_m2 BETWEEN 30000 AND 500000
|
||||
AND o.region_cd = 66
|
||||
AND f.snapshot_date > CURRENT_DATE - INTERVAL '24 months'
|
||||
GROUP BY 1, 2, 3
|
||||
HAVING COUNT(*) >= 30 -- статистически значимая выборка
|
||||
),
|
||||
|
||||
z_scores AS (
|
||||
SELECT
|
||||
district_name, obj_class, bucket,
|
||||
n_deals, avg_price_per_m2, avg_area_m2, avg_velocity_per_month,
|
||||
-- Z-score нормированный по группе (district × class)
|
||||
(avg_velocity_per_month
|
||||
- AVG(avg_velocity_per_month) OVER (PARTITION BY district_name, obj_class))
|
||||
/ NULLIF(STDDEV(avg_velocity_per_month) OVER (PARTITION BY district_name, obj_class), 0)
|
||||
AS velocity_z,
|
||||
(avg_price_per_m2
|
||||
- AVG(avg_price_per_m2) OVER (PARTITION BY district_name, obj_class))
|
||||
/ NULLIF(STDDEV(avg_price_per_m2) OVER (PARTITION BY district_name, obj_class), 0)
|
||||
AS price_z,
|
||||
(avg_area_m2
|
||||
- AVG(avg_area_m2) OVER (PARTITION BY district_name, obj_class))
|
||||
/ NULLIF(STDDEV(avg_area_m2) OVER (PARTITION BY district_name, obj_class), 0)
|
||||
AS area_z
|
||||
FROM bucket_aggs
|
||||
)
|
||||
|
||||
SELECT
|
||||
district_name,
|
||||
obj_class,
|
||||
bucket,
|
||||
n_deals,
|
||||
avg_price_per_m2,
|
||||
avg_area_m2,
|
||||
avg_velocity_per_month,
|
||||
COALESCE(velocity_z, 0) * 0.5
|
||||
+ COALESCE(price_z, 0) * 0.3
|
||||
- COALESCE(area_z, 0) * 0.2 AS success_score,
|
||||
COALESCE(velocity_z, 0) AS velocity_z,
|
||||
COALESCE(price_z, 0) AS price_z,
|
||||
COALESCE(area_z, 0) AS area_z
|
||||
FROM z_scores
|
||||
ORDER BY district_name, obj_class, success_score DESC;
|
||||
|
||||
COMMENT ON VIEW v_bucket_success_score IS
|
||||
'Success-driven bucket ranking per (district, class). '
|
||||
'Z-scores: velocity (+) приоритет, price (+) приоритет, area (-) приоритет. '
|
||||
'Min 30 сделок в группе. '
|
||||
'Используется recommend_mix для смещения рекомендации (issue #25).';
|
||||
|
||||
COMMIT;
|
||||
Loading…
Add table
Reference in a new issue