has issues
This commit is contained in:
parent
2e112d7398
commit
c645b0f1d4
96 changed files with 2147083 additions and 5787 deletions
|
|
@ -5,9 +5,13 @@ use rustc_hash::FxHashMap;
|
|||
use tracing::error;
|
||||
|
||||
use crate::consts::PRICE_HISTORY_POINTS_LIMIT;
|
||||
use crate::data::crime_by_year::CrimeByYearData;
|
||||
use crate::data::{FeatureStats, PostcodePoiMetrics, PropertyData};
|
||||
|
||||
use super::hexagon_stats::{EnumFeatureStats, HistogramStats, NumericFeatureStats, PricePoint};
|
||||
use super::hexagon_stats::{
|
||||
CrimeYearPoint, CrimeYearStats, EnumFeatureStats, HistogramStats, NumericFeatureStats,
|
||||
PricePoint,
|
||||
};
|
||||
|
||||
/// Extract price history (year, price) pairs from matching rows, downsampled if needed.
|
||||
pub fn extract_price_history(
|
||||
|
|
@ -251,6 +255,91 @@ pub fn compute_feature_stats(
|
|||
(numeric_features, enum_features_out)
|
||||
}
|
||||
|
||||
/// Compute property-weighted per-year crime means across the selection.
|
||||
///
|
||||
/// Each matching property contributes its LSOA's per-year counts; this is the
|
||||
/// same property-weighted-LSOA-average shape used elsewhere in the right pane.
|
||||
/// LSOAs with no series for a given crime type contribute 0 for that type
|
||||
/// (matching how the existing `(avg/yr)` columns treat missing crime types).
|
||||
pub fn compute_crime_by_year(
|
||||
matching_rows: &[usize],
|
||||
data: &PropertyData,
|
||||
crime_by_year: &CrimeByYearData,
|
||||
fields_specified: bool,
|
||||
field_set: &HashSet<String>,
|
||||
) -> Vec<CrimeYearStats> {
|
||||
if crime_by_year.crime_types.is_empty() || matching_rows.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
// For each crime type, accumulate per-year sums and the count of rows whose
|
||||
// LSOA exists in the crime side table.
|
||||
let num_types = crime_by_year.crime_types.len();
|
||||
let mut per_type_year_sums: Vec<FxHashMap<i32, f64>> =
|
||||
(0..num_types).map(|_| FxHashMap::default()).collect();
|
||||
let mut per_type_row_counts: Vec<u32> = vec![0; num_types];
|
||||
|
||||
for &row in matching_rows {
|
||||
let lsoa = data.lsoa(row);
|
||||
let Some(series_list) = crime_by_year.series_by_lsoa.get(lsoa) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// For every type the LSOA reports, add its per-year counts.
|
||||
// For types it doesn't report, treat the row as contributing 0 — so we
|
||||
// bump the row count for *every* known type below.
|
||||
for series in series_list {
|
||||
let acc = &mut per_type_year_sums[series.type_idx as usize];
|
||||
for point in &series.points {
|
||||
*acc.entry(point.year).or_insert(0.0) += point.count as f64;
|
||||
}
|
||||
}
|
||||
for c in per_type_row_counts.iter_mut() {
|
||||
*c += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut out = Vec::new();
|
||||
for (type_idx, name) in crime_by_year.crime_types.iter().enumerate() {
|
||||
// Crime types in the by-year side table are bare (e.g. "Burglary"), while
|
||||
// the configured feature names carry an " (avg/yr)" suffix. Match either
|
||||
// form so callers can pass the feature names they already know.
|
||||
if fields_specified {
|
||||
let with_suffix = format!("{name} (avg/yr)");
|
||||
if !field_set.contains(name.as_str()) && !field_set.contains(with_suffix.as_str()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let row_count = per_type_row_counts[type_idx];
|
||||
if row_count == 0 {
|
||||
continue;
|
||||
}
|
||||
let years = crime_by_year
|
||||
.years_by_type
|
||||
.get(type_idx)
|
||||
.map(Vec::as_slice)
|
||||
.unwrap_or(&[]);
|
||||
if years.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let denom = row_count as f64;
|
||||
let sums = &per_type_year_sums[type_idx];
|
||||
let points: Vec<CrimeYearPoint> = years
|
||||
.iter()
|
||||
.map(|&year| CrimeYearPoint {
|
||||
year,
|
||||
count: (sums.get(&year).copied().unwrap_or(0.0) / denom) as f32,
|
||||
})
|
||||
.collect();
|
||||
out.push(CrimeYearStats {
|
||||
name: name.clone(),
|
||||
points,
|
||||
});
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
pub fn compute_poi_feature_stats(
|
||||
matching_rows: &[usize],
|
||||
poi_metrics: &PostcodePoiMetrics,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue