Code
source("setup.R")source("setup.R")library(boot)
library(CompQuadForm)
library(dda)library(fdANOVA)
library(fda.usc)library(MVN)library(sf)library(tidyverse)library(colorspace)
set.seed(10983)
data(vietnam_temperature_dd)
data(vietnam_regions)
data(vietnam_provinces)
lat_order_code <- c("NMM", "RRD", "NCC", "CHR", "SR", "MDR")
lat_order <- c(
"Northern Midlands and Mountains",
"Red River Delta",
"North Central Coast",
"Central Highlands",
"Southeast",
"Mekong Delta"
)
vietnam_regions$name <- factor(str_wrap(vietnam_regions$name, 20), levels = str_wrap(lat_order, 20))
vietnam_regions$code <- factor(vietnam_regions$code, levels = lat_order_code)
vietnam_temperature_dd$region <- factor(vietnam_temperature_dd$region,
levels = lat_order_code
)
vietnam_provinces |>
left_join(vietnam_regions, by = c("region" = "code")) |>
rename(region_name = name) |>
ggplot(aes(fill = region_name)) +
scale_fill_viridis_d(option = "magma", end = 0.8) +
theme_legend_inside +
geom_sf() +
scale_x_continuous(breaks = seq(from = -180, to = 180, by = 2)) +
labs(x = "Longitude", y = "Latitude", fill = "Region")vntry <- vietnam_temperature_dd |>
left_join(vietnam_regions, by = c("region" = "code")) |>
rename(region_name = name) |>
arrange(region, province) |>
select(!province) |>
group_by(region, region_name, year) |>
summarise(t_max = mean(t_max))vntry |>
plot_funs(t_max, color = year) +
facet_grid(vars(region), axes = "all") +
scale_linewidth(range = c(0.1, 1.2)) +
scale_y_continuous(n.breaks = 4) +
scale_color_viridis_c(end = 0.8) +
labs(
x = "Temperature (deg. Celsius)",
y = "Density",
color = "Year"
)to_slope <- function(ddobj, t = seq_len(ncol(ddobj$coefs))) {
model <- lm(t(ddobj$coefs) ~ t)
# Density-on-scalar regression
slope <- ddobj
slope$coefs <- model$coefficients["t", ]
# Compute functional R^2
eps <- ddobj
eps$coefs <- t(model$residuals)
ssr_evol <- diag(inprod(eps, eps))
sst_evol <- diag(inprod(ddobj, ddobj))
ssr <- sum(ssr_evol)
sst <- sum(sst_evol)
slope <- dd(clr = fd(slope$coefs, slope$basis))
attr(slope, "rsq") <- 1 - ssr / sst
attr(slope, "ssr_evol") <- data.frame(t = t, ssr = ssr_evol / sst_evol)
slope
}
vnt <- vietnam_temperature_dd |>
group_by(region, province) |>
summarise(t_max = list(c(t_max)), .groups = "drop") |>
rowwise() |>
mutate(t_max = list(to_slope(t_max))) |>
mutate(rsq = attr(t_max, "rsq")) |>
mutate(ssr_evol = list(attr(t_max, "ssr_evol"))) |>
ungroup() |>
left_join(vietnam_regions, by = c("region" = "code")) |>
rename(region_name = name) |>
arrange(region, province)
class(vnt$t_max) <- c("ddl", "fdl", "list")
vnt |> plot_funs(t_max, color = region_name) +
facet_grid(vars(region), axes = "all") +
scale_color_viridis_d(option = "magma", end = 0.8) +
scale_y_continuous(n.breaks = 4) +
theme(legend.position = "none") +
geom_hline(yintercept = 1 / diff(vnt$t_max[[1]]$basis$rangeval), linetype = "dotted") +
labs(
x = "Temperature (deg. Celsius)",
y = "Density"
)vntr <- vnt |>
select(!province) |>
group_by(region, region_name) |>
summarise(t_max = mean(t_max))vntr |> plot_funs(t_max, color = region_name) +
geom_hline(yintercept = 1 / diff(vnt$t_max[[1]]$basis$rangeval), linetype = "dotted") +
facet_grid(vars(region), axes = "all") +
scale_color_viridis_d(option = "magma", end = 0.8) +
scale_y_continuous(n.breaks = 4) +
theme(legend.position = "none") +
labs(
x = "Temperature (deg. Celsius)",
y = "Density"
)one_sample <- function(ddobj, p = 3) {
n <- ncol(ddobj$coefs)
d <- nrow(ddobj$coefs)
pca_fit <- pca.fd(ddobj, nharm = d)
lambda <- pca_fit$values
scores <- pca_fit$scores
v <- pca_fit$harmonics
# PC test
tpc <- n * sum(inprod(v[1:p], mean(ddobj))^2 / lambda[1:p])
tpc_pval <- pchisq(tpc, p, lower.tail = FALSE)
# Norm test
tnorm <- n * sum(inprod(v[lambda[1:d] > 0], mean(ddobj))^2)
tnorm_pval <- imhof(tnorm, lambda[lambda[1:d] > 0])[[1]]
one_sample_tbl <- tibble(
Name = c("PC", "Norm"),
Statistic = c(tpc, tnorm),
`p-value` = c(tpc_pval, tnorm_pval)
)
}one_sample_regional_tbl <- vnt |>
select(region, region_name, t_max) |>
summarise(t_max = list(c(t_max)), .by = c(region, region_name)) |>
rowwise() |>
mutate(res = list(one_sample(t_max))) |>
unnest(res) |>
select(region, Name, `p-value`) |>
pivot_wider(names_from = Name, values_from = `p-value`)
multiple_testing <- function(tbl, m) {
mutate(tbl, across(where(is.numeric), ~ 1 - (1 - .x)^m))
}
kable_format(multiple_testing(one_sample_regional_tbl,
m = nrow(one_sample_regional_tbl)
))| region | PC | Norm |
|---|---|---|
| NMM | 7.9e-02 * | 0.12 |
| RRD | 1.6e-10 *** | 1.5e-04 *** |
| NCC | 8e-02 * | 0.12 |
| CHR | 0.65 | 0.99 |
| SR | 1.8e-03 *** | 4.2e-04 *** |
| MDR | 0e+00 *** | 4.9e-08 *** |
vnte <- vnt |>
mutate(t_max = as.fd(t_max)) |>
eval_funs(t_max, n = 1401) |>
select(province, x, y) |>
pivot_wider(names_from = province, values_from = y) |>
column_to_rownames("x")
vnt_province_region <- vietnam_provinces$region
names(vnt_province_region) <- vietnam_provinces$province
stat_list <- list("GPF", "Fmaxb", "CS", "L2B", "FB")
res <- fanova.tests(vnte, vnt_province_region[colnames(vnte)],
test = stat_list,
params = list(
paramCS = 100,
paramFmaxb = 100,
paramTRP = list(B.TRP = 100)
)
)
danova_tbl <- res[as_vector(stat_list)] |>
sapply(function(x) c(`Statistic` = x$stat, `p-value` = x$pval)) |>
t() |>
as.data.frame() |>
rownames_to_column("Name")
kable_format(danova_tbl)| Name | Statistic | p-value |
|---|---|---|
| GPF | 10 | 0e+00 *** |
| Fmaxb | 36 | 0e+00 *** |
| CS | 700 | 0e+00 *** |
| L2B | 130 | 0e+00 *** |
| FB | 9.9 | 0e+00 *** |
vntp <- t(combn(c("NMM", "RRD", "NCC", "CHR", "SR", "MDR"), m = 2))
colnames(vntp) <- c("region1", "region2")
pairwise_anova <- function(region1, region2) {
data <- vnte[vnt_province_region[colnames(vnte)] %in% c(region1, region2)]
res <- fanova.tests(data, vnt_province_region[colnames(data)],
test = stat_list,
params = list(
paramCS = 100,
paramFmaxb = 100,
paramTRP = list(B.TRP = 100)
)
)
res[as_vector(stat_list)] |>
sapply(function(x) c(x$pval)) |>
c()
}
multiple_testing <- function(tbl, m) {
mutate(tbl, across(where(is.numeric), ~ 1 - (1 - .x)^m))
}
pairwise_tbl <- as_tibble(vntp) |>
rowwise() |>
mutate(res = map2(region1, region2, pairwise_anova)) |>
unnest_wider(res)
kable_format(multiple_testing(pairwise_tbl, m = nrow(pairwise_tbl)))| region1 | region2 | GPF | Fmaxb | CS | L2B | FB |
|---|---|---|---|---|---|---|
| NMM | RRD | 0.33 | 0.85 | 0e+00 *** | 1e-01 * | 0.18 |
| NMM | NCC | 1 | 0.97 | 1 | 1 | 1 |
| NMM | CHR | 0.48 | 0.37 | 0.96 | 0.97 | 0.99 |
| NMM | SR | 3e-05 *** | 0e+00 *** | 0.26 | 0.71 | 0.83 |
| NMM | MDR | 0e+00 *** | 0e+00 *** | 0e+00 *** | 5.4e-09 *** | 1.4e-06 *** |
| RRD | NCC | 2.8e-02 ** | 0e+00 *** | 0e+00 *** | 2.5e-03 *** | 8.6e-03 *** |
| RRD | CHR | 3.3e-02 ** | 0e+00 *** | 1 | 0.82 | 0.89 |
| RRD | SR | 0e+00 *** | 0e+00 *** | 0e+00 *** | 8.7e-11 *** | 3.9e-06 *** |
| RRD | MDR | 0e+00 *** | 0e+00 *** | 0e+00 *** | 0e+00 *** | 0e+00 *** |
| NCC | CHR | 0.98 | 0.96 | 0.99 | 0.99 | 1 |
| NCC | SR | 0.49 | 0.14 | 0.14 | 0.6 | 0.71 |
| NCC | MDR | 2e-13 *** | 0e+00 *** | 0e+00 *** | 7.9e-13 *** | 2.6e-09 *** |
| CHR | SR | 0.27 | 0.54 | 0.46 | 0.15 | 0.4 |
| CHR | MDR | 4.8e-11 *** | 0e+00 *** | 0e+00 *** | 3.7e-11 *** | 2.3e-07 *** |
| SR | MDR | 2.7e-06 *** | 0.14 | 0e+00 *** | 9e-04 *** | 6.2e-03 *** |
flowchart TB
NMM([NMM]) ~~~ MDR([MDR])
NMM <-.-> SR([SR])
NMM <--> CHR([CHR]) <--> SR
NMM <-.-> RRD([RRD]) <-.-> CHR
RRD <--> NCC
NCC <--> CHR
NMM <--> NCC([NCC]) <--> SR
SR <-.-> MDR
NMM ~~~ MDR([MDR])
style NMM fill:#000004,color:#fff,stroke:#000
style RRD fill:#29115b,color:#fff,stroke:#000
style NCC fill:#6d1c82,color:#fff,stroke:#000
style CHR fill:#ac337b,stroke:#000
style SR fill:#ea5662,stroke:#000
style MDR fill:#ff9f6f,stroke:#000flowchart TB NMM([NMM]) ~~~ MDR([MDR]) NMM <-.-> SR([SR]) NMM <--> CHR([CHR]) <--> SR NMM <-.-> RRD([RRD]) <-.-> CHR RRD <--> NCC NCC <--> CHR NMM <--> NCC([NCC]) <--> SR SR <-.-> MDR NMM ~~~ MDR([MDR]) style NMM fill:#000004,color:#fff,stroke:#000 style RRD fill:#29115b,color:#fff,stroke:#000 style NCC fill:#6d1c82,color:#fff,stroke:#000 style CHR fill:#ac337b,stroke:#000 style SR fill:#ea5662,stroke:#000 style MDR fill:#ff9f6f,stroke:#000
fmin <- function(...) UseMethod("fmin")
fmax <- function(...) UseMethod("fmax")
fargmin <- function(...) UseMethod("fargmin")
fargmax <- function(...) UseMethod("fargmax")
fmin.fdl <- function(...) fmin(c(...))
fmax.fdl <- function(...) fmax(c(...))
fargmin.fdl <- function(...) fargmin(c(...))
fargmax.fdl <- function(...) fargmax(c(...))
fsolve <- function(...) UseMethod("fsolve")
fsolve.fdl <- function(...) fargmax(c(...))
fmin.fd <- function(fdobj,
a = min(fdobj$basis$rangeval),
b = max(fdobj$basis$rangeval)) {
f <- function(x) eval(fdobj, x)
results <- lapply(
seq_along(f(a)),
function(i) optimize(function(x) f(x)[i], interval = c(a, b))
)
sapply(results, `[[`, "objective")
}
fargmin.fd <- function(fdobj,
a = min(fdobj$basis$rangeval),
b = max(fdobj$basis$rangeval)) {
f <- function(x) eval(fdobj, x)
results <- lapply(
seq_along(f(a)),
function(i) optimize(function(x) f(x)[i], interval = c(a, b))
)
sapply(results, `[[`, "minimum")
}
fmax.fd <- function(fdobj,
a = min(fdobj$basis$rangeval),
b = max(fdobj$basis$rangeval)) {
f <- function(x) -eval(fdobj, x)
results <- lapply(
seq_along(f(a)),
function(i) optimize(function(x) f(x)[i], interval = c(a, b))
)
-sapply(results, `[[`, "objective")
}
fargmax.fd <- function(fdobj,
a = min(fdobj$basis$rangeval),
b = max(fdobj$basis$rangeval)) {
f <- function(x) -eval(fdobj, x)
results <- lapply(
seq_along(f(a)),
function(i) optimize(function(x) f(x)[i], interval = c(a, b))
)
sapply(results, `[[`, "minimum")
}
fsolve.fd <- function(fdobj, k,
a = min(fdobj$basis$rangeval),
b = max(fdobj$basis$rangeval)) {
f <- function(x) eval(fdobj, x) - k
results <- lapply(
seq_along(f(a)),
function(i) uniroot(function(x) f(x)[i], interval = c(a, b))
)
sapply(results, `[[`, "root")
}thres1 <- 0.5 * (fmax(vntr$t_max[[1]], 30, 35) + fmin(vntr$t_max[[1]], 20, 30))
thres3 <- 0.5 * (fmax(vntr$t_max[[3]], 30, 35) + fmin(vntr$t_max[[3]], 20, 30))
vnt_mountains_thresholds <- rbind(tibble(
region = "NMM",
x = c(
fsolve(vntr$t_max[[1]], fmax(vntr$t_max[[1]], 30, 35), 20, 25),
fsolve(vntr$t_max[[1]], thres1, 20, 25),
fsolve(vntr$t_max[[1]], thres1, 25, 30),
fsolve(vntr$t_max[[1]], thres1, 30, 35),
fsolve(vntr$t_max[[1]], fmin(vntr$t_max[[1]], 20, 30), 30, 35)
),
y = c(
fmax(vntr$t_max[[1]], 30, 35),
thres1,
thres1,
thres1,
fmin(vntr$t_max[[1]], 20, 30)
)
), tibble(
region = "NCC",
x = c(
fsolve(vntr$t_max[[3]], fmax(vntr$t_max[[3]], 30, 35), 15, 25),
fsolve(vntr$t_max[[3]], thres3, 20, 25),
fsolve(vntr$t_max[[3]], thres3, 25, 30),
fsolve(vntr$t_max[[3]], thres3, 30, 35),
fsolve(vntr$t_max[[3]], fmin(vntr$t_max[[3]], 25, 30), 30, 35)
),
y = c(
fmax(vntr$t_max[[3]], 30, 35),
thres3,
thres3,
thres3,
fmin(vntr$t_max[[3]], 25, 30)
)
))
vnt_mountains_thresholds |> mutate(x = signif(x, 3), y = signif(y, 3))| region | x | y |
|---|---|---|
| NMM | 21.5 | 0.0354 |
| NMM | 22.6 | 0.0353 |
| NMM | 27.6 | 0.0353 |
| NMM | 33.5 | 0.0353 |
| NMM | 34.1 | 0.0351 |
| NCC | 19.9 | 0.0360 |
| NCC | 21.0 | 0.0357 |
| NCC | 29.1 | 0.0357 |
| NCC | 32.9 | 0.0357 |
| NCC | 33.7 | 0.0354 |
vntr |>
filter(region %in% c("NMM", "NCC")) |>
plot_funs(t_max) +
geom_vline(data = vnt_mountains_thresholds, aes(xintercept = x, color = y, linetype = -y)) +
geom_hline(data = vnt_mountains_thresholds, aes(yintercept = y, color = y, linetype = -y)) +
facet_grid(vars(region), axes = "all") +
scale_linetype_binned() +
scale_y_continuous(n.breaks = 4) +
theme(legend.position = "none") +
labs(
x = "Temperature (deg. Celsius)",
y = "Density"
)vnt_rrd_thresholds <- rbind(tibble(
region = "RRD",
x = c(
fsolve(vntr$t_max[[2]], fmax(vntr$t_max[[2]], 12, 15), 35, 37),
fsolve(vntr$t_max[[2]], fmax(vntr$t_max[[2]], 12, 15), 37, 40),
fsolve(vntr$t_max[[2]], fmin(vntr$t_max[[2]], 37, 40), 15, 20),
fsolve(vntr$t_max[[2]], fmin(vntr$t_max[[2]], 37, 40), 30, 35)
),
y = c(
fmax(vntr$t_max[[2]], 12, 15),
fmax(vntr$t_max[[2]], 12, 15),
fmin(vntr$t_max[[2]], 37, 40),
fmin(vntr$t_max[[2]], 37, 40)
)
), tibble(
region = "CHR",
x = c(
fsolve(vntr$t_max[[4]], fmax(vntr$t_max[[4]], 20, 30), 35, 40),
fsolve(vntr$t_max[[4]], fmin(vntr$t_max[[4]], 30, 40), 15, 20),
fsolve(vntr$t_max[[4]], fmin(vntr$t_max[[4]], 30, 40), 20, 25)
),
y = c(
fmax(vntr$t_max[[4]], 20, 30),
fmin(vntr$t_max[[4]], 30, 40),
fmin(vntr$t_max[[4]], 30, 40)
)
))
vnt_rrd_thresholds |> mutate(x = signif(x, 3), y = signif(y, 3))| region | x | y |
|---|---|---|
| RRD | 35.6 | 0.0365 |
| RRD | 39.7 | 0.0365 |
| RRD | 17.3 | 0.0359 |
| RRD | 34.6 | 0.0359 |
| CHR | 38.7 | 0.0363 |
| CHR | 17.5 | 0.0355 |
| CHR | 23.5 | 0.0355 |
vntr |>
filter(region %in% c("RRD", "CHR")) |>
plot_funs(t_max) +
geom_vline(data = vnt_rrd_thresholds, aes(xintercept = x, color = y, linetype = -y)) +
geom_hline(data = vnt_rrd_thresholds, aes(yintercept = y, color = y, linetype = -y)) +
facet_grid(vars(region), axes = "all") +
scale_linetype_binned() +
scale_y_continuous(n.breaks = 4) +
theme(legend.position = "none") +
labs(
x = "Temperature (deg. Celsius)",
y = "Density"
)vnt_south_thresholds <- rbind(tibble(
region = "SR",
x = c(
fsolve(vntr$t_max[[5]], fmax(vntr$t_max[[5]], 12, 20), 20, 25),
fsolve(vntr$t_max[[5]], fmax(vntr$t_max[[5]], 12, 20), 25, 30),
fsolve(vntr$t_max[[5]], fmin(vntr$t_max[[5]], 12, 25), 30, 35)
),
y = c(
fmax(vntr$t_max[[5]], 12, 20),
fmax(vntr$t_max[[5]], 12, 20),
fmin(vntr$t_max[[5]], 12, 25)
)
), tibble(
region = "MDR",
x = c(
fsolve(vntr$t_max[[6]], fmax(vntr$t_max[[6]], 12, 20), 25, 30),
fsolve(vntr$t_max[[6]], fmax(vntr$t_max[[6]], 12, 20), 30, 35),
fsolve(vntr$t_max[[6]], fmin(vntr$t_max[[6]], 12, 25), 30, 35)
),
y = c(
fmax(vntr$t_max[[6]], 12, 20),
fmax(vntr$t_max[[6]], 12, 20),
fmin(vntr$t_max[[6]], 12, 25)
)
))
vnt_south_thresholds |> mutate(x = signif(x, 3), y = signif(y, 3))| region | x | y |
|---|---|---|
| SR | 22.9 | 0.0365 |
| SR | 27.5 | 0.0365 |
| SR | 34.2 | 0.0356 |
| MDR | 25.5 | 0.0371 |
| MDR | 32.6 | 0.0371 |
| MDR | 33.0 | 0.0363 |
vntr |>
filter(region %in% c("SR", "MDR")) |>
plot_funs(t_max) +
geom_vline(data = vnt_south_thresholds, aes(xintercept = x, color = y, linetype = -y)) +
geom_hline(data = vnt_south_thresholds, aes(yintercept = y, color = y, linetype = -y)) +
facet_grid(vars(region), axes = "all") +
scale_linetype_binned() +
scale_y_continuous(n.breaks = 4) +
theme(legend.position = "none") +
labs(
x = "Temperature (deg. Celsius)",
y = "Density"
)vnt_mean <- mean(c(vnt$t_max))
plot(vnt_mean) +
geom_hline(yintercept = 1 / diff(vnt$t_max[[1]]$basis$rangeval), linetype = "dotted") +
scale_y_continuous(n.breaks = 4) +
labs(
x = "Temperature (deg. Celsius)",
y = "Density"
)
plot(as.fd(as.list(vnt_mean))) +
scale_y_continuous(n.breaks = 4) +
labs(
x = "Temperature (deg. Celsius)",
y = "clr"
)kable_format(one_sample(c(vnt$t_max)))| Name | Statistic | p-value |
|---|---|---|
| PC | 38 | 3.1e-08 *** |
| Norm | 1.3 | 1.3e-06 *** |
thres0 <- 0.5 * (fmax(vnt_mean, 25, 30) + fmin(vnt_mean, 20, 25))
vnt_mean_thresholds <- tibble(
x = c(
fsolve(vnt_mean, fmax(vnt_mean, 25, 30), 15, 20),
fsolve(vnt_mean, thres0, 15, 22),
fsolve(vnt_mean, thres0, 22, 30),
fsolve(vnt_mean, thres0, 30, 35),
fsolve(vnt_mean, fmin(vnt_mean, 20, 25), 30, 35)
),
y = c(
fmax(vnt_mean, 25, 30),
thres0,
thres0,
thres0,
fmin(vnt_mean, 20, 25)
)
)
vnt_mean_thresholds |> signif(3)| x | y |
|---|---|
| 18.2 | 0.0362 |
| 19.6 | 0.0359 |
| 25.4 | 0.0359 |
| 32.9 | 0.0359 |
| 33.4 | 0.0355 |
plot(vnt_mean) +
geom_vline(data = vnt_mean_thresholds, aes(xintercept = x, color = y, linetype = -y)) +
geom_hline(data = vnt_mean_thresholds, aes(yintercept = y, color = y, linetype = -y)) +
scale_linetype_binned() +
scale_y_continuous(n.breaks = 4) +
theme(legend.position = "none") +
labs(
x = "Temperature (deg. Celsius)",
y = "Density"
)vnt |>
select(!province) |>
mutate(t_max = center(t_max)) |>
group_by(region, region_name) |>
summarise(t_max = mean(t_max), .groups = "drop") |>
mutate(t_max = as.fd(t_max)) |>
plot_funs(t_max, color = region_name) +
scale_color_viridis_d(option = "magma", end = 0.8) +
scale_y_continuous(n.breaks = 4) +
theme(legend.position = "none") +
labs(
x = "Temperature (deg. Celsius)",
y = "Centered log-ratio transform"
)vnt |>
select(!rsq) |>
unnest(ssr_evol) |>
ggplot(aes(t, ssr, color = region, group = province)) +
geom_point() +
geom_line() +
facet_grid(vars(region))vietnam_provinces |>
left_join(vnt, by = "province") |>
ggplot(aes(fill = rsq)) +
geom_sf() +
scale_fill_viridis_c() +
scale_x_continuous(breaks = seq(from = -180, to = 180, by = 2)) +
labs(x = "Longitude", y = "Latitude", fill = "R squared")vnt_pc <- pca.fd(c(vnt$t_max), nharm = 5)
pairs(vnt_pc$scores)
mvn(vnt_pc$scores, mvnTest = "mardia")vnt_var <- var.fd(c(as.fd(vnt$t_max)))
tt <- seq(
vnt_var$sbasis$rangeval[1],
vnt_var$sbasis$rangeval[2],
length.out = 401
)
z <- eval.bifd(tt, tt, vnt_var) # Covariance
z <- cor.fd(tt, c(as.fd(vnt$t_max))) # Correlation
df <- data.frame(
x = rep(tt, each = length(tt)),
y = rep(tt, times = length(tt)),
z = as.vector(z)
)
ggplot(df, aes(x = x, y = y, z = z)) +
geom_contour_filled() +
coord_fixed() +
labs(
fill = "Correlation",
x = "Temperature (deg. Celsius)", y = "Temperature (deg. Celsius)"
)library(sf)
library(units)vnt_sdist <- vnt |>
left_join(select(vietnam_provinces, !region), by = "province") |>
st_as_sf() |>
st_centroid() |>
st_distance() |>
set_units("km") |>
drop_units()ggplot(reshape2::melt(vnt_sdist), aes(x = Var1, y = Var2, fill = value)) +
geom_tile() +
scale_fill_viridis_c(option = "magma") +
scale_y_reverse() +
coord_fixed() + labs(fill = "Distance (km)") + theme_void()
# Computing ANOVA residuals
vnt_rmeans <- vnt |>
select(!province) |>
group_by(region, region_name) |>
mutate(t_max = mean(t_max))
fd_obj <- as.fd(c(vnt$t_max - vnt_rmeans$t_max))
n <- nrow(vnt)
# Computing pairwise Bayes distances between residuals
vnt_fdist <- matrix(0, n, n)
for(i in 1:(n-1)){
for(j in (i+1):n){
diff_fd <- fd_obj[i] - fd_obj[j]
vnt_fdist[i,j] <- sqrt(inprod(diff_fd, diff_fd))
vnt_fdist[j,i] <- vnt_fdist[i,j]
}
}
ggplot(reshape2::melt(vnt_fdist), aes(x = Var1, y = Var2, fill = value)) +
geom_tile() +
scale_fill_viridis_c(option = "magma") +
scale_y_reverse() +
coord_fixed() + labs(fill = "Bayes distance") + theme_void()library(gstat)
library(dplyr)
variogram_dist <- function(dist_mat, fdist_mat, cutoff = NULL, width = NULL, nbins = 15) {
n <- nrow(dist_mat)
# Check that both matrices are square and of the same size
if (!is.matrix(dist_mat) || !is.matrix(fdist_mat) ||
ncol(dist_mat) != n || nrow(fdist_mat) != n || ncol(fdist_mat) != n) {
stop("dist_mat and fdist_mat must be square matrices of the same size.")
}
# Compute gamma matrix from feature-distance matrix
gamma_mat <- 0.5 * fdist_mat^2
# Default cutoff and bin width similar to gstat
dmax <- max(dist_mat, na.rm = TRUE)
if (is.null(cutoff)) cutoff <- dmax / 3
if (is.null(width)) width <- cutoff / nbins
# Create bin breaks
breaks <- seq(0, cutoff, by = width)
if (tail(breaks, 1) < cutoff) breaks <- c(breaks, cutoff)
# Extract upper-triangle indices (i < j)
idx <- which(upper.tri(dist_mat), arr.ind = TRUE)
d_ij <- dist_mat[idx] # spatial distances
gamma_ij <- gamma_mat[idx] # computed semivariances
# Assign each pair to a bin
bin_id <- cut(d_ij, breaks = breaks, include.lowest = TRUE)
# Compute mean gamma per bin
gamma_means <- tapply(gamma_ij, bin_id, mean, na.rm = TRUE)
npairs <- tapply(gamma_ij, bin_id, length)
# Bin centers
bin_centers <- (head(breaks, -1) + tail(breaks, -1)) / 2
# Return as data.frame
data.frame(
dist = bin_centers,
gamma = as.numeric(gamma_means),
np = as.numeric(npairs)
)
}
vg <- variogram_dist(vnt_sdist, vnt_fdist)
ggplot(vg, aes(x=dist, y=gamma)) + geom_point() + labs(x = "Distance (km)", y = "Semivariance")@article{mondon2025,
author = {Mondon, Camille and Trinh, Huong Thi and Martín-Fernández,
Josep Antoni and Thomas-Agnan, Christine},
title = {Testing the Equality of Mean Densities with an Application to
Climate Change in {Vietnam}},
journal = {Stochastic Environmental Research and Risk Assessment},
date = {2025-12-09},
langid = {en}
}