R Inla and Balancing data set
Nasra Mapoy <[email protected]> Sun, 19 Apr 2026 23:57:15 +0300
| Newsgroups | gmane.comp.lang.r.general |
|---|---|
| Message-ID | <CAMpGuXaaOz9h2N6UdxkZ50=FwHC2CEhzO2txAG_uyjJJAs+VnA@mail.gmail.com> |
Hi,
My name is Nasra. I am working on my thesis using R for analysis, I have an
objective of predicting household inequality, using R inla and machine
learning. But my data is imbalanced (i have about 94 inadequate housing
coded as 1) i want to balance then proceed with analysis. Unfortunately I
got stuck each time. Please help me.
Down is just an example of my data set
head(df_analysis)# A tibble: 6 × 40
H_REGION_NAME H_DISTRICT_NAME H_WARD_NAME H_VILLAGE_NAME H_LATITUDE
<fct> <fct> <fct> <fct> <dbl>1
Kusini Pemba Chake Chake Chanjaani Vijijini -5.262
Kusini Pemba Chake Chake Chanjaani Vijijini -5.263
Kusini Pemba Chake Chake Chanjaani Vijijini -5.264
Kusini Pemba Chake Chake Chanjaani Vijijini -5.265
Kusini Pemba Chake Chake Chanjaani Vijijini -5.266
Kusini Pemba Chake Chake Chanjaani Vijijini -5.26# ℹ
35 more variables: H_LONGITUDE <dbl>, LOCATION <fct>, MEMBERS <dbl>,#
TENURE <fct>, LAND <fct>, ROOF <fct>, FLOOR <fct>, WALLS <fct>,#
ROOMS <dbl>, DRINKING_WATER <fct>, COOKING <fct>, LIGHTING <fct>,#
TOILET <fct>, SOLID_WASTE <fct>, HEAD_SEX <fct>, HEAD_AGE <dbl>,#
HEAD_EDUCATION <fct>, HEAD_ECON_ACTV <fct>, HEAD_MARITAL <fct>,#
HEAD_OCCUPATION <fct>, H_Education <fct>, Durability_Floor <fct>,#
Durability_Wall <fct>, Durability_Roof <fct>, Improved_Water <fct>,
these ara some of the codes which i run
library(spldv)
library(readr)
library(spdep)
library(spDataLarge)
library(haven)
library(sp)
library(INLA) # INLA models
library(sf) # spatial data
library(ggplot2) # plotting
library(dplyr)
#library(DMwR)
library(smotefamily)
library(sf)
library(sp)
library(INLA)
# 1. Read shapefile and prepare coordinates
shp_data <- st_read("housing.shp")
shp_data_sp <- as(shp_data, "Spatial")
coords <- st_coordinates(shp_data)
# Add coordinates to dataframe
shp_data$X <- coords[,1]
shp_data$Y <- coords[,2]
names(shp_data)[names(shp_data) == "slum"] <- "housing_inadequacy"
# Convert categorical variables to factors
shp_data$LOCATION <- as.factor(shp_data$LOCATIO)
shp_data$HEAD_SEX <- as.factor(shp_data$HEAD_SE)
shp_data$age_grouped <- as.factor(shp_data$ag_grpd)
shp_data$HEAD_MARITAL<- as.factor(shp_data$HEAD_MA)
shp_data$HEAD_EDUCATION <- as.factor(shp_data$H_Edctn)
shp_data$HEAD_ECON_ACTV <- as.factor(shp_data$HEAD_EC)
shp_data$hhsize <- as.factor(shp_data$hhsize)
# Create numeric district id
shp_data$id <- as.numeric(as.factor(shp_data$H_DISTR))
# Response variable (binary 0/1)
shp_data$y <- as.integer(shp_data$housing_inadequacy)
coords <- st_coordinates(st_centroid(shp_data))
# 2. Build mesh
mesh <- inla.mesh.2d(
loc = coords,
max.edge = c(0.05, 0.2),
cutoff = 0.01
)
str(coords)
# 3. Define SPDE model
spde <- inla.spde2.pcmatern(
mesh = mesh,
alpha = 2,
prior.range = c(0.5, 0.01), # P(range < 0.5) = 0.01
prior.sigma = c(1, 0.01) # P(sigma > 1) = 0.01
)
# 4. Create spatial index and projector matrix
spatial_index <- inla.spde.make.index("spatial_field", n.spde = spde$n.spde)
A <- inla.spde.make.A(mesh = mesh, loc = coords)
# 5. Build stack
stack <- inla.stack(
data = list(y = shp_data$y),
A = list(1, A),
effects = list(
data.frame(
Intercept = 1,
LOCATION = shp_data$LOCATION,
age_grouped = shp_data$age_grouped,
HEAD_SEX = shp_data$HEAD_SEX,
HEAD_EDUCATION = shp_data$HEAD_EDUCATION,
hhsize = shp_data$hhsize,
HEAD_ECON_ACTV = shp_data$HEAD_ECON_ACTV,
HEAD_MARITAL = shp_data$HEAD_MARITAL,
id = shp_data$id
),
spatial_index
),
tag = "est"
)
# 6. Define formulas
## Baseline (no random effects)
formula_baseline <- y ~ LOCATION + age_grouped + HEAD_SEX +
HEAD_EDUCATION + hhsize + HEAD_ECON_ACTV + HEAD_MARITAL
## Unstructured (IID only)
formula_unstructured <- y ~ LOCATION + age_grouped + HEAD_SEX +
HEAD_EDUCATION + hhsize + HEAD_ECON_ACTV + HEAD_MARITAL +
f(id, model = "iid")
## Structured (SPDE only)
formula_structured <- y ~ LOCATION + age_grouped + HEAD_SEX +
HEAD_EDUCATION + hhsize + HEAD_ECON_ACTV + HEAD_MARITAL +
f(spatial_field, model = spde)
## Full (SPDE + IID)
formula_full <- y ~ LOCATION + age_grouped + HEAD_SEX +
HEAD_EDUCATION + hhsize + HEAD_ECON_ACTV + HEAD_MARITAL +
f(id, model = "iid") +
f(spatial_field, model = spde)
# 7. Fit models
result_baseline <- inla(formula_baseline, family = "binomial",
data = inla.stack.data(stack),
control.predictor = list(A =
inla.stack.A(stack), compute = TRUE),
control.compute = list(dic = TRUE, waic = TRUE))
result_unstructured <- inla(formula_unstructured, family = "binomial",
data = inla.stack.data(stack),
control.predictor = list(A =
inla.stack.A(stack), compute = TRUE),
control.compute = list(dic = TRUE, waic = TRUE))
result_structured <- inla(formula_structured, family = "binomial",
data = inla.stack.data(stack),
control.predictor = list(A =
inla.stack.A(stack), compute = TRUE),
control.compute = list(dic = TRUE, waic = TRUE))
result_full <- inla(formula_full, family = "binomial",
data = inla.stack.data(stack),
control.predictor = list(A = inla.stack.A(stack),
compute = TRUE),
control.compute = list(dic = TRUE, waic = TRUE))
# 8. Compare models
model_comparison <- data.frame(
Model = c("Baseline", "Unstructured", "Structured", "Full"),
DIC = c(result_baseline$dic$dic,
result_unstructured$dic$dic,
result_structured$dic$dic,
result_full$dic$dic),
WAIC = c(result_baseline$waic$waic,
result_unstructured$waic$waic,
result_structured$waic$waic,
result_full$waic$waic)
)
print(model_comparison)
# Baseline model predictions
pred_baseline <- result_baseline$summary.fitted.values
# Unstructured model predictions
pred_unstructured <- result_unstructured$summary.fitted.values
# Structured model predictions
pred_structured <- result_structured$summary.fitted.values
# Full model predictions
pred_full <- result_full$summary.fitted.values
# Add posterior mean predictions
# Extract fitted values for each model
fv_baseline <- result_baseline$summary.fitted.values
fv_unstructured <- result_unstructured$summary.fitted.values
fv_structured <- result_structured$summary.fitted.values
fv_full <- result_full$summary.fitted.values
# Align with estimation stack
idx <- inla.stack.index(stack, tag = "est")$data
# Posterior mean predictions
shp_data$pred_baseline <- fv_baseline$mean[idx]
shp_data$pred_unstructured <- fv_unstructured$mean[idx]
shp_data$pred_structured <- fv_structured$mean[idx]
shp_data$pred_full <- fv_full$mean[idx]
# Credible intervals
shp_data$pred_baseline_lower <- fv_baseline$`0.025quant`[idx]
shp_data$pred_baseline_upper <- fv_baseline$`0.975quant`[idx]
shp_data$pred_unstructured_lower <- fv_unstructured$`0.025quant`[idx]
shp_data$pred_unstructured_upper <- fv_unstructured$`0.975quant`[idx]
shp_data$pred_structured_lower <- fv_structured$`0.025quant`[idx]
shp_data$pred_structured_upper <- fv_structured$`0.975quant`[idx]
shp_data$pred_full_lower <- fv_full$`0.025quant`[idx]
shp_data$pred_full_upper <- fv_full$`0.975quant`[idx]
##Plotting
library(sf)
library(ggplot2)
library(patchwork) # for arranging plots
tanzania_boundaries <- st_read("C:/Users/Malilo/Desktop/New
folder/PHD_2026/TPHC_10/tza_admbnda_adm1_20181019/tza_admbnda_adm1_20181019.shp")
# Create centroids for region labels
library(sf)
library(ggplot2)
library(viridis)
library(ggspatial) # for north arrow and scale bar
# Create centroids for labels
tanzania_centroids <- st_centroid(tanzania_boundaries)
# Convert back to sf object
shp_data_sf <- st_as_sf(shp_data)
# Baseline model
p_baseline <- ggplot() +
geom_sf(data = tanzania_boundaries, fill = NA, color = "black",
linewidth = 0.6) +
geom_sf(data = shp_data_sf, aes(color = pred_baseline)) +
geom_sf_text(data = tanzania_centroids, aes(label = ADM1_EN),
size = 2, color = "black", check_overlap = TRUE) +
scale_color_viridis_c(option = "magma") +
theme_minimal() +
theme(
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1)
) +
labs(title = "Housing Inadequacy (Baseline Model)", color = "Probability")
print(p_baseline)
# Unstructured model
p_unstructured <- ggplot() +
geom_sf(data = tanzania_boundaries, fill = NA, color = "black",
linewidth = 0.6) +
geom_sf(data = shp_data_sf, aes(color = pred_unstructured)) +
geom_sf_text(data = tanzania_centroids, aes(label = ADM1_EN),
size = 2, color = "black", check_overlap = TRUE) +
scale_color_viridis_c(option = "magma") +
theme_minimal() +
theme(
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1)
) +
labs(title = "Housing Inadequacy (Unstructured Model)", color = "Probability")
print(p_unstructured)
# Structured model
p_structured <- ggplot() +
geom_sf(data = tanzania_boundaries, fill = NA, color = "black",
linewidth = 0.6) +
geom_sf(data = shp_data_sf, aes(color = pred_structured)) +
geom_sf_text(data = tanzania_centroids, aes(label = ADM1_EN),
size = 2, color = "black", check_overlap = TRUE) +
scale_color_viridis_c(option = "magma") +
theme_minimal() +
theme(
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1)
) +
labs(title = "Housing Inadequacy (Structured Model)", color = "Probability")
print(p_structured)
# Full model
p_full <- ggplot() +
geom_sf(data = tanzania_boundaries, fill = NA, color = "black",
linewidth = 0.6) +
geom_sf(data = shp_data_sf, aes(color = pred_full)) +
geom_sf_text(data = tanzania_centroids, aes(label = ADM1_EN),
size = 2, color = "black", check_overlap = TRUE) +
scale_color_viridis_c(option = "magma") +
theme_minimal() +
theme(
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1)
) +
labs(title = "Housing Inadequacy (Full Model)", color = "Probability")
print(p_full)
# Define mapping of coded names to descriptive labels
label_map <- c(
"(Intercept)" = "(Intercept)",
"LOCATION2" = "Location: Urban",
"HEAD_SEX2" = "Head sex: Female",
"age_grouped2"= "Age group: 15–24",
"age_grouped3"= "Age group: 25–44",
"age_grouped4"= "Age group: 45–64",
"age_grouped5"= "Age group: 65+",
"hhsize2" = "Household size: 2 - 3 persons",
"hhsize3" = "Household size: 4 - 5 persons",
"hhsize4" = "Household size: 6 persons or above",
"HEAD_MARITAL2"= "Marital Status: Married",
"HEAD_MARITAL3"= "Marital Status: Living together",
"HEAD_MARITAL4"= "Marital Status: Divorced",
"HEAD_MARITAL5"= "Marital Status: Separated",
"HEAD_MARITAL6"= "Marital Status: Widowed",
"HEAD_EDUCATION2"= "Education: Secondary",
"HEAD_EDUCATION3"= "Education: Tertiary",
"HEAD_ECON_ACTV2"= "Self-employed (No workers) ",
"HEAD_ECON_ACTV3"= "Self-employed (With workers) ",
"HEAD_ECON_ACTV4"= "Unskilled labour",
"HEAD_ECON_ACTV5"= "Unrecognized employees"
)
# Function to relabel rownames
relabel_fixed <- function(fixed_table, map){
fixed_table$Predictor <- map[rownames(fixed_table)]
rownames(fixed_table) <- NULL
return(fixed_table)
}
fixed_baseline_lbl <- relabel_fixed(result_baseline$summary.fixed,
label_map)
fixed_unstructured_lbl <-
relabel_fixed(result_unstructured$summary.fixed, label_map)
fixed_structured_lbl <-
relabel_fixed(result_structured$summary.fixed, label_map)
fixed_full_lbl <- relabel_fixed(result_full$summary.fixed, label_map)
library(openxlsx)
wb <- createWorkbook()
addWorksheet(wb, "Baseline")
addWorksheet(wb, "Unstructured")
addWorksheet(wb, "Structured")
addWorksheet(wb, "Full")
writeData(wb, "Baseline", fixed_baseline_lbl)
writeData(wb, "Unstructured", fixed_unstructured_lbl)
writeData(wb, "Structured", fixed_structured_lbl)
writeData(wb, "Full", fixed_full_lbl)
saveWorkbook(wb, "Fixed_Effects_Models_Labeled.xlsx", overwrite = TRUE)
library(ggplot2)
# Relabel function
relabel_for_plot <- function(fixed_table, map){
df <- fixed_table
df$Predictor <- map[rownames(df)]
rownames(df) <- NULL
return(df)
}
# Relabel each model’s fixed effects
fixed_baseline_lbl <-
relabel_for_plot(result_baseline$summary.fixed, label_map)
fixed_unstructured_lbl <-
relabel_for_plot(result_unstructured$summary.fixed, label_map)
fixed_structured_lbl <-
relabel_for_plot(result_structured$summary.fixed, label_map)
fixed_full_lbl <- relabel_for_plot(result_full$summary.fixed, label_map)
# Plot Baseline
ggplot(fixed_baseline_lbl, aes(y = Predictor, x = mean)) +
geom_point(color = "blue") +
geom_errorbarh(aes(xmin = `0.025quant`, xmax = `0.975quant`), height = 0.2) +
theme_minimal() +
labs(title = "Posterior Estimates with 95% Credible Intervals
(Baseline Model)",
y = "Predictors", x = "Posterior Mean")
# Plot Unstructured
ggplot(fixed_unstructured_lbl, aes(y = Predictor, x = mean)) +
geom_point(color = "blue") +
geom_errorbarh(aes(xmin = `0.025quant`, xmax = `0.975quant`), height = 0.2) +
theme_minimal() +
labs(title = "Posterior Estimates with 95% Credible Intervals
(Unstructured Model)",
y = "Predictors", x = "Posterior Mean")
# Plot Structured
ggplot(fixed_structured_lbl, aes(y = Predictor, x = mean)) +
geom_point(color = "blue") +
geom_errorbarh(aes(xmin = `0.025quant`, xmax = `0.975quant`), height = 0.2) +
theme_minimal() +
labs(title = "Posterior Estimates with 95% Credible Intervals
(Structured Model)",
y = "Predictors", x = "Posterior Mean")
# Plot Full
ggplot(fixed_full_lbl, aes(y = Predictor, x = mean)) +
geom_point(color = "blue") +
geom_errorbarh(aes(xmin = `0.025quant`, xmax = `0.975quant`), height = 0.2) +
theme_minimal() +
labs(title = "Posterior Estimates with 95% Credible Intervals (Full Model)",
y = "Predictors", x = "Posterior Mean")
library(pROC)
# Example for Full model
roc_full <- roc(response = shp_data_sf$y, predictor = shp_data_sf$pred_full)
plot(roc_full, col = "blue", main = "ROC Curve - Full Model")
auc(roc_full) # Print AUC value
# Compare across models
roc_baseline <- roc(response = shp_data_sf$y, predictor =
shp_data_sf$pred_baseline)
roc_unstructured <- roc(response = shp_data_sf$y, predictor =
shp_data_sf$pred_unstructured)
roc_structured <- roc(response = shp_data_sf$y, predictor =
shp_data_sf$pred_structured)
plot(roc_baseline, col = "red", main = "ROC Curves Comparison")
plot(roc_unstructured, col = "green", add = TRUE)
plot(roc_structured, col = "purple", add = TRUE)
plot(roc_full, col = "blue", add = TRUE)
legend("bottomright", legend = c("Baseline","Unstructured","Structured","Full"),
col = c("red","green","purple","blue"), lwd = 2)
##Baseline Model
# Fixed effects
fixed_baseline_lbl <- relabel_for_plot(result_baseline$summary.fixed, label_map)
ggplot(fixed_baseline_lbl, aes(y = Predictor, x = mean)) +
geom_point(color = "blue") +
geom_errorbarh(aes(xmin = `0.025quant`, xmax = `0.975quant`), height = 0.2) +
labs(title = "Posterior Estimates (Baseline Model)", y =
"Predictors", x = "Posterior Mean") +
theme_minimal()
# Predicted probabilities (per observation)
pred_df_baseline <- data.frame(ID = 1:nrow(shp_data),
mean = shp_data$pred_baseline)
ggplot(pred_df_baseline, aes(x = ID, y = mean)) +
geom_point(color = "blue") +
labs(title = "Predicted Probabilities (Baseline Model)",
x = "Observation Index", y = "Posterior Mean") +
theme_minimal()
# Histogram of predictions
ggplot(pred_df_baseline, aes(x = mean)) +
geom_histogram(binwidth = 0.05, fill = "skyblue", color = "black") +
labs(title = "Distribution of Predicted Probabilities (Baseline Model)",
x = "Predicted Probability", y = "Count") +
theme_minimal()
# ROC curve
roc_baseline <- roc(response = shp_data$y, predictor = shp_data$pred_baseline)
plot(roc_baseline, col = "red", main = "ROC Curve (Baseline)")
auc(roc_baseline)
##Unstructured Model
# Fixed effects
fixed_unstructured_lbl <-
relabel_for_plot(result_unstructured$summary.fixed, label_map)
ggplot(fixed_unstructured_lbl, aes(y = Predictor, x = mean)) +
geom_point(color = "blue") +
geom_errorbarh(aes(xmin = `0.025quant`, xmax = `0.975quant`), height = 0.2) +
labs(title = "Posterior Estimates (Unstructured Model)", y =
"Predictors", x = "Posterior Mean") +
theme_minimal()
# Predicted probabilities (per observation)
pred_df_unstructured <- data.frame(ID = 1:nrow(shp_data),
mean = shp_data$pred_unstructured)
ggplot(pred_df_unstructured, aes(x = ID, y = mean)) +
geom_point(color = "red") +
labs(title = "Predicted Probabilities (Unstructured Model)",
x = "Observation Index", y = "Posterior Mean") +
theme_minimal()
# Histogram
ggplot(pred_df_unstructured, aes(x = mean)) +
geom_histogram(binwidth = 0.05, fill = "salmon", color = "black") +
labs(title = "Distribution of Predicted Probabilities (Unstructured Model)",
x = "Predicted Probability", y = "Count") +
theme_minimal()
# Random effects (IID)
rand_df_unstructured <- as.data.frame(result_unstructured$summary.random$id)
rand_df_unstructured$Index <- 1:nrow(rand_df_unstructured)
ggplot(rand_df_unstructured, aes(x = Index, y = mean)) +
geom_point(color = "blue") +
labs(title = "Unstructured Random Effect (IID)",
x = "District Index", y = "Posterior Mean") +
theme_minimal()
# Extract IID random effects
# Convert shapefile data to sf object
shp_data_sf <- st_as_sf(shp_data)
# Map predicted probabilities from the Unstructured model
ggplot() +
geom_sf(data = tanzania_boundaries, fill = NA, color = "black",
linewidth = 0.6) +
geom_sf(data = shp_data_sf, aes(color = pred_unstructured)) +
geom_sf_text(data = tanzania_centroids, aes(label = ADM1_EN),
size = 2, color = "black", check_overlap = TRUE) +
scale_color_viridis_c(option = "magma") +
theme_minimal() +
theme(
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1)
) +
labs(title = "Distribution of Predicted Probabilities (Unstructured Model)",
color = "Probability")
# ROC curve
roc_unstructured <- roc(response = shp_data$y, predictor =
shp_data$pred_unstructured)
plot(roc_unstructured, col = "green", main = "ROC Curve (Unstructured)")
auc(roc_unstructured)
hyper_unstructured <- result_unstructured$summary.hyperpar
print(as.data.frame(hyper_unstructured))
##Structured Model
# Fixed effects
fixed_structured_lbl <-
relabel_for_plot(result_structured$summary.fixed, label_map)
ggplot(fixed_structured_lbl, aes(y = Predictor, x = mean)) +
geom_point(color = "blue") +
geom_errorbarh(aes(xmin = `0.025quant`, xmax = `0.975quant`), height = 0.2) +
labs(title = "Posterior Estimates (Structured Model)", y =
"Predictors", x = "Posterior Mean") +
theme_minimal()
# Predicted probabilities (per observation)
pred_df_structured <- data.frame(ID = 1:nrow(shp_data),
mean = shp_data$pred_structured)
ggplot(pred_df_structured, aes(x = ID, y = mean)) +
geom_point(color = "green") +
labs(title = "Predicted Probabilities (Structured Model)",
x = "Observation Index", y = "Posterior Mean") +
theme_minimal()
# Histogram
ggplot(pred_df_structured, aes(x = mean)) +
geom_histogram(binwidth = 0.05, fill = "lightgreen", color = "black") +
labs(title = "Distribution of Predicted Probabilities (Structured Model)",
x = "Predicted Probability", y = "Count") +
theme_minimal()
# Random effects (SPDE field)
rand_df_structured <-
as.data.frame(result_structured$summary.random$spatial_field)
rand_df_structured$Index <- 1:nrow(rand_df_structured)
ggplot(rand_df_structured, aes(x = Index, y = mean)) +
geom_point(color = "darkgreen") +
labs(title = "Structured Random Effect (SPDE)",
x = "Spatial Index", y = "Posterior Mean") +
theme_minimal()
# Map predicted probabilities (Structured)
ggplot() +
geom_sf(data = tanzania_boundaries, fill = NA, color = "black",
linewidth = 0.6) +
geom_sf(data = shp_data_sf, aes(color = pred_structured)) +
geom_sf_text(data = tanzania_centroids, aes(label = ADM1_EN),
size = 2, color = "black", check_overlap = TRUE) +
scale_color_viridis_c(option = "magma") +
labs(title = "Predicted Probabilities (Structured Model)", color =
"Probability") +
theme_minimal()
# ROC curve
roc_structured <- roc(response = shp_data$y, predictor =
shp_data$pred_structured)
plot(roc_structured, col = "purple", main = "ROC Curve (Structured)")
auc(roc_structured)
# Extract hyperparameters for Structured model
hyper_structured <- result_structured$summary.hyperpar
# Convert to data frame
hyper_structured_df <- as.data.frame(hyper_structured)
# Add descriptive row names
rownames(hyper_structured_df) <- c("Theta1 for spatial", "Theta2 for spatial")
# Print table
print(hyper_structured_df)
# Optional: export to Excel
library(openxlsx)
wb <- createWorkbook()
addWorksheet(wb, "Structured Hyperparameters")
writeData(wb, "Structured Hyperparameters", hyper_structured_df,
rowNames = TRUE)
saveWorkbook(wb, "Structured_Hyperparameters.xlsx", overwrite = TRUE)
##Full Model
# Fixed effects
fixed_full_lbl <- relabel_for_plot(result_full$summary.fixed, label_map)
ggplot(fixed_full_lbl, aes(y = Predictor, x = mean)) +
geom_point(color = "blue") +
geom_errorbarh(aes(xmin = `0.025quant`, xmax = `0.975quant`), height = 0.2) +
labs(title = "Posterior Estimates (Full Model)", y = "Predictors", x
= "Posterior Mean") +
theme_minimal()
# Predicted probabilities (per observation)
pred_df_full <- data.frame(ID = 1:nrow(shp_data),
mean = shp_data$pred_full)
ggplot(pred_df_full, aes(x = ID, y = mean)) +
geom_point(color = "black") +
labs(title = "Predicted Probabilities (Full Model)",
x = "Observation Index", y = "Posterior Mean") +
theme_minimal()
# Histogram
ggplot(pred_df_full, aes(x = mean)) +
geom_histogram(binwidth = 0.05, fill = "gray", color = "black") +
labs(title = "Distribution of Predicted Probabilities (Full Model)",
x = "Predicted Probability", y = "Count") +
theme_minimal()
# Random effects (IID)
rand_df_full_iid <- as.data.frame(result_full$summary.random$id)
rand_df_full_iid$Index <- 1:nrow(rand_df_full_iid)
ggplot(rand_df_full_iid, aes(x = Index, y = mean)) +
geom_point(color = "purple") +
labs(title = "Full Model Random Effect (IID)",
x = "District Index", y = "Posterior Mean") +
theme_minimal()
# Random effects (SPDE)
rand_df_full_spatial <- as.data.frame(result_full$summary.random$spatial_field)
rand_df_full_spatial$Index <- 1:nrow(rand_df_full_spatial)
ggplot(rand_df_full_spatial, aes(x = Index, y = mean)) +
geom_point(color = "orange") +
labs(title = "Full Model Random Effect (SPDE)",
x = "Spatial Index", y = "Posterior Mean") +
theme_minimal()
# Map predicted probabilities (Full)
ggplot() +
geom_sf(data = tanzania_boundaries, fill = NA, color = "black",
linewidth = 0.6) +
geom_sf(data = shp_data_sf, aes(color = pred_full)) +
geom_sf_text(data = tanzania_centroids, aes(label = ADM1_EN),
size = 2, color = "black", check_overlap = TRUE) +
scale_color_viridis_c(option = "magma") +
labs(title = "Predicted Probabilities (Full Model)", color = "Probability") +
theme_minimal()
# ROC curve
roc_full <- roc(response = shp_data$y, predictor = shp_data$pred_full)
plot(roc_full, col = "blue", main = "ROC Curve (Full)")
auc(roc_full)
hyper_full <- result_full$summary.hyperpar
print(as.data.frame(hyper_full))
library(pROC)
library(yardstick)
library(dplyr)
# Function to compute metrics for any INLA model
evaluate_inla <- function(model, stack, df_inla, model_name) {
# Prediction indices
index_pred <- inla.stack.index(stack, "pred")$data
# True labels
true_labels <- df_inla$y[index_pred]
# Posterior predicted probabilities
pred_probs <- model$summary.fitted.values$mean[index_pred]
# ROC + AUC
roc_obj <- roc(true_labels, pred_probs)
auc_val <- auc(roc_obj)
# Optimal threshold (Youden’s J)
opt_thresh <- coords(roc_obj, "best", ret = "threshold")
# Classify
pred_class <- ifelse(pred_probs > opt_thresh, 1, 0)
# Evaluation dataframe
df_eval <- data.frame(
truth = factor(true_labels, levels = c(0,1)),
pred_class = factor(pred_class, levels = c(0,1)),
pred_prob = pred_probs
)
# Metrics
acc <- accuracy(df_eval, truth, pred_class)$.estimate
prec <- precision(df_eval, truth, pred_class)$.estimate
rec <- recall(df_eval, truth, pred_class)$.estimate
f1 <- f_meas(df_eval, truth, pred_class, beta = 1)$.estimate
# Collect results
data.frame(
Model = model_name,
Threshold = round(opt_thresh,3),
Accuracy = round(acc,3),
Precision = round(prec,3),
Recall = round(rec,3),
F1 = round(f1,3),
AUC = round(auc_val,3)
)
}
results_baseline <- evaluate_inla(result_baseline, stack,
shp_data_sf, "INLA Baseline")
results_unstructured<- evaluate_inla(result_unstructured, stack,
shp_data_sf, "INLA Unstructured")
results_structured <- evaluate_inla(result_spatial, stack,
shp_data_sf, "INLA Structured")
results_full <- evaluate_inla(result_full, stack, shp_data_sf,
"INLA Full")
# Combine into one table
results_all <- bind_rows(results_baseline, results_unstructured,
results_structured, results_full)
print(results_all)
#Machine Learning
library(spldv)
library(readr)
library(spdep)
library(spDataLarge)
library(haven)
library(sp)
library(INLA) # INLA models
library(sf) # spatial data
library(ggplot2) # plotting
library(dplyr)
library(DMwR)
library(smotefamily)
library(caret)
# 1. Read shapefile and prepare coordinates
shp_data <- st_read("housing.shp")
# Convert categorical variables to factors
shp_data$LOCATION <- as.factor(shp_data$LOCATIO)
shp_data$HEAD_SEX <- as.factor(shp_data$HEAD_SE)
shp_data$age_grouped <- as.factor(shp_data$ag_grpd)
shp_data$HEAD_MARITAL<- as.factor(shp_data$HEAD_MA)
shp_data$HEAD_EDUCATION <- as.factor(shp_data$H_Edctn)
shp_data$HEAD_ECON_ACTV <- as.factor(shp_data$HEAD_EC)
shp_data$hhsize <- as.factor(shp_data$hhsize)
names(shp_data)
table(shp_data$slum)
table(shp_data$slum)
#install.packages("remotes")
#remotes::install_version("DMwR", version = "0.4.1", repos =
"http://cran.us.r-project.org")
set.seed(123)
# 1. Drop geometry column
shp_data_no_geom <- shp_data %>% select(-geometry)
# 2. Train/test split (70/30)
trainIndex <- createDataPartition(shp_data_no_geom$slum, p = 0.7, list = FALSE)
train <- shp_data_no_geom[trainIndex, ]
test <- shp_data_no_geom[-trainIndex, ]
# 3. Apply SMOTE only to training set (formula interface)
# Auto-tune perc.over and perc.under for perfect balance
minority_count <- sum(train$slum == 0)
majority_count <- sum(train$slum == 1)
perc.over <- ((majority_count - minority_count) / minority_count) * 100
perc.under <- 100
train_df <- as.data.frame(train)
train_df$slum <- factor(train_df$slum, levels = c(0,1))
# Convert all character columns to factors
char_cols <- sapply(train_df, is.character)
train_df[char_cols] <- lapply(train_df[char_cols], factor)
list_cols <- sapply(train_df, is.list)
train_df <- train_df[ , !list_cols]
table(train_bal$slum)
library(sf)
library(dplyr)
# Ensure slum is numeric in train_bal
train_bal$slum <- as.numeric(as.character(train_bal$slum))
# Join balanced attributes back to geometry
train_bal_sf <- shp_data %>%
inner_join(train_bal, by = c("LOCATION","age_grouped","HEAD_SEX",
"HEAD_EDUCATION","hhsize","HEAD_ECON_ACTV",
"HEAD_MARITAL","slum"))
# Save as shapefile
st_write(train_bal_sf, "train_balanced.shp", delete_layer = TRUE)
# Load the shapefile you just wrote
train_bal_sf <- st_read("train_balanced.shp")
# Inspect column names
names(train_bal_sf)
# Check balance
table(train_bal_sf$slum)
names(train_balanced.shp)
###Modelling
library(caret)
library(randomForest)
library(xgboost)
library(pROC)
set.seed(123)
# Define baseline formula
formula_baseline <- slum ~ LOCATION + age_grouped + HEAD_SEX +
HEAD_EDUCATION + hhsize + HEAD_ECON_ACTV + HEAD_MARITAL
# -------------------------------
# 1. Logistic Regression (GLM)
# -------------------------------
logit_model <- glm(formula_baseline, data = train_bal, family = binomial)
logit_pred <- predict(logit_model, newdata = test, type = "response")
logit_class <- ifelse(logit_pred > 0.5, 1, 0)
confusionMatrix(factor(logit_class), factor(test$slum))
roc(test$slum, logit_pred)
# -------------------------------
# 2. Random Forest
# -------------------------------
rf_model <- randomForest(formula_baseline, data = train_bal,
ntree = 500, mtry = 3, importance = TRUE)
rf_pred <- predict(rf_model, newdata = test, type = "prob")[,2]
rf_class <- ifelse(rf_pred > 0.5, 1, 0)
confusionMatrix(factor(rf_class), factor(test$slum))
roc(test$slum, rf_pred)
# -------------------------------
# 3. XGBoost
# -------------------------------
# For XGBoost we need dummy encoding
train_X <- model.matrix(formula_baseline, data = train_bal)[, -1]
train_y <- as.numeric(as.character(train_bal$slum))
test_X <- model.matrix(formula_baseline, data = test)[, -1]
test_y <- as.numeric(as.character(test$slum))
xgb_train <- xgb.DMatrix(data = train_X, label = train_y)
xgb_test <- xgb.DMatrix(data = test_X, label = test_y)
xgb_model <- xgboost(data = xgb_train, nrounds = 200,
objective = "binary:logistic", eval_metric = "auc")
xgb_pred <- predict(xgb_model, newdata = xgb_test)
xgb_class <- ifelse(xgb_pred > 0.5, 1, 0)
confusionMatrix(factor(xgb_class), factor(test_y))
roc(test_y, xgb_pred)
Structure
str(df_analysis)tibble [1,417,184 × 40] (S3: tbl_df/tbl/data.frame)
$ H_REGION_NAME : Factor w/ 32 levels "Kusini Pemba",..: 1 1 1 1
1 1 1 1 1 1 ...
$ H_DISTRICT_NAME : Factor w/ 151 levels "Chake Chake",..: 1 1 1 1
1 1 1 1 1 1 ...
$ H_WARD_NAME : Factor w/ 3995 levels "Chanjaani","Shungi",..:
1 1 1 1 1 1 1 1 1 1 ...
$ H_VILLAGE_NAME : Factor w/ 15570 levels "Vijijini","Muembe
Tongwa",..: 1 1 1 1 1 1 1 1 1 1 ...
$ H_LATITUDE : num [1:1417184] -5.26 -5.26 -5.26 -5.26 -5.26 ...
$ H_LONGITUDE : num [1:1417184] 39.8 39.8 39.8 39.8 39.8 ...
$ LOCATION : Factor w/ 2 levels "Urban","Rural": 1 1 1 1 1 1
1 1 1 1 ...
$ MEMBERS : num [1:1417184] 10 3 5 12 1 6 7 4 8 10 ...
$ TENURE : Factor w/ 7 levels "Owned by household",..: 1 2
1 1 2 2 1 2 1 1 ...
$ LAND : Factor w/ 8 levels "Title deed","No legal
right",..: 1 NA 2 3 NA NA 1 NA 3 2 ...
$ ROOF : Factor w/ 8 levels "Iron sheets",..: 1 1 1 1 2
1 1 1 1 1 ...
$ FLOOR : Factor w/ 10 levels "Cement","Earth/Sand",..: 1
1 1 1 2 1 1 1 1 1 ...
$ WALLS : Factor w/ 10 levels "Cement bricks/Rock
bricks",..: 1 1 1 1 1 1 1 2 1 1 ...
$ ROOMS : num [1:1417184] 2 3 3 5 2 1 2 3 4 6 ...
$ DRINKING_WATER : Factor w/ 14 levels "Public tap/standpipe",..:
1 1 2 3 1 3 2 2 3 4 ...
$ COOKING : Factor w/ 14 levels "Firewood","Charcoal",..: 1
2 1 1 2 1 1 1 2 1 ...
$ LIGHTING : Factor w/ 13 levels "Kerosene (Wick lamps)",..:
1 2 3 2 3 2 2 1 2 2 ...
$ TOILET : Factor w/ 11 levels "Flush/pour flush to
covered pit",..: 1 1 1 1 2 1 1 3 1 1 ...
$ SOLID_WASTE : Factor w/ 9 levels "Irregularly collected",..:
1 2 3 3 3 3 2 4 4 4 ...
$ HEAD_SEX : Factor w/ 2 levels "Female Headed",..: 1 2 2 2
2 2 2 1 2 2 ...
$ HEAD_AGE : num [1:1417184] 44 24 34 44 24 38 47 41 64 44 ...
$ HEAD_EDUCATION : Factor w/ 29 levels "14","10","7",..: NA 1 2 2
2 3 2 2 2 4 ...
$ HEAD_ECON_ACTV : Factor w/ 5 levels "Paid employees",..: NA NA
NA NA NA NA NA NA NA NA ...
$ HEAD_MARITAL : Factor w/ 7 levels "Divorced","Married",..: 1 2
2 2 3 2 2 2 2 2 ...
$ HEAD_OCCUPATION : Factor w/ 9 levels "Technicians and associate
professionals.",..: 1 1 2 3 NA NA 4 NA 2 3 ...
$ H_Education : Factor w/ 4 levels "Secondary","Primary",..: NA
1 1 1 1 2 1 1 1 2 ...
$ Durability_Floor : Factor w/ 2 levels "Durable","Not durable": 1 1
1 1 2 1 1 1 1 1 ...
$ Durability_Wall : Factor w/ 2 levels "Durable","Not durable": 1 1
1 1 1 1 1 2 1 1 ...
$ Durability_Roof : Factor w/ 2 levels "Durable","Not durable": 1 1
1 1 2 1 1 1 1 1 ...
$ Improved_Water : Factor w/ 2 levels "Improved","Unimproved": 1 1
1 1 1 1 1 1 1 2 ...
$ Toilet_Facility : Factor w/ 2 levels "Unimproved","Improved": 1 1
1 1 2 1 1 2 1 1 ...
$ Secure_Tenure : Factor w/ 2 levels "Not secure","Secure": 1 NA
2 1 NA NA 1 NA 1 2 ...
$ age_grouped : Factor w/ 5 levels "25-44","15-24",..: 1 2 1 1
2 1 3 1 3 1 ...
$ Bed_Rooms : num [1:1417184] 0 1 1 1 0 0 0 1 1 1 ...
$ hhsize : Factor w/ 4 levels "6 and above persons",..: 1
2 3 1 4 1 1 3 1 1 ...
$ Living_Area : Factor w/ 278 levels
"5","1","1.66666662693024",..: 1 2 3 4 5 6 7 8 9 3 ...
$ Living_Area1 : Factor w/ 2 levels "Overcrowding",..: 1 2 2 2 2
1 1 2 2 2 ...
$ Durable_Materials : Factor w/ 2 levels "Durable","Not Durable": 1 1
1 1 2 1 1 2 1 1 ...
$ housing_inadequacy: Factor w/ 2 levels "Inadequate","Adequate": 1 1
1 1 1 1 1 1 1 1 ...
$ number_slum1 : num [1:1417184] 3 1 1 2 1 2 3 1 2 2 ...
>
sample data set
source("sample_dataset.R")
I am looking forward to get your feedback
Regards
Nasra
[[alternative HTML version deleted]]