archive_start <- as.Date("2020-05-01")
# Prepare each Arrow dataset with renamed columns before joining
ds_old_prep <- df_old_smoothed |>
filter(time_value >= archive_start) |>
mutate(geo_value = cast(geo_value, utf8()),
version = cast(version, date32())) |>
select(geo_value, time_value, version, value) |>
rename(value_old = value)
# cast(version, date32()) collapses multiple dttm values to the same date,
# so deduplicate after collecting to avoid many-to-many join expansion.
ds_new_prep <- df_new |>
filter(time_value >= archive_start) |>
mutate(
geo_value = cast(geo_value, utf8()),
version = cast(version, date32()),
value_new = coalesce(value_smoothed, value)
) |>
select(geo_value, time_value, version, value_new) |>
collect() |>
mutate(across(c(time_value, version), as.Date)) |>
distinct(geo_value, time_value, version, .keep_all = TRUE)
ds_old_prep_collected <- ds_old_prep |>
collect() |>
mutate(across(c(time_value, version), as.Date))
# Join in R after deduplication
archive_joined <- ds_old_prep_collected |>
inner_join(ds_new_prep, by = c("geo_value", "time_value", "version")) |>
mutate(
val_latest_old = value_old,
val_latest_new = value_new,
abs_diff = val_latest_new - val_latest_old,
rel_diff = abs_diff / (abs(val_latest_old) + 1e-6),
diff = abs_diff
) |>
select(geo_value, time_value, version,
val_latest_old, val_latest_new, abs_diff, rel_diff, diff)
# Free the Arrow dataset handles
rm(ds_old_prep, ds_old_prep_collected, ds_new_prep, df_old_smoothed, df_new)
invisible(gc())
archive_metrics <- get_summary_metrics(archive_joined)
# Compute rolling IQR on a stratified sample to avoid memory problems
sampled_versions <- archive_joined |>
distinct(geo_value, version) |>
group_by(geo_value) |>
mutate(row_id = sample(n())) |>
filter(row_id <= 20L) |>
ungroup() |>
select(-row_id)
archive_iqr <- archive_joined |>
semi_join(sampled_versions, by = c("geo_value", "version")) |>
mutate(abs_diff = abs(diff)) |>
group_by(geo_value, version) |>
arrange(time_value) |>
mutate(
IQR_val = slider::slide_dbl(val_latest_old, IQR_wrapper, .before = 59, .complete = FALSE)
) |>
tidyr::fill(IQR_val, .direction = "downup") |>
mutate(
IQR_backup = suppressWarnings(min(IQR_val[IQR_val > 0], na.rm = TRUE)),
IQR_val = dplyr::if_else(IQR_val == 0 | is.na(IQR_val), IQR_backup, IQR_val),
abs_diff_scaled = abs_diff / IQR_val
) |>
ungroup()
rm(sampled_versions)
invisible(gc())