library(tidyverse)
library(seminr)
library(kableExtra)
library(readxl)
library(janitor)
library(viridis)
library(DescTools)
library(tidygraph)
library(ggraph)
This supplementary material documents the workflow for estimating the Partial Least Squares Structural Equation Model (PLS-SEM) and implementing robustness checks that complement the main article. It reports (i) data preparation and outlier handling, (ii) measurement model evaluation, (iii) bootstrapped structural model results, and (iv) robustness analyses using alternative outlier treatments (winsorization and listwise deletion). All procedures follow established guidelines for formative PLS-SEM, applying two-tailed inference where appropriate (Hair et al., 2019; Hair et al., 2021).
Methodological note. PLS-SEM was chosen in line with recommendations by Hair et al. (2021). The
seminrpackage was employed due to its transparent syntax for specifying constructs and estimating paths. To guarantee reproducibility of bootstrap procedures, the random seed was fixed atset.seed(35).
Data Import and Cleaning. The dataset includes
N = 5,570 municipal-level observations. A selection of
32 indicators was extracted and renamed to align with
the construct structure: Infrastructure and Support
(INFRA), Environmental Governance (ENVIR),
Ecosystems Conservation Practices (ECOSY), Farming Systems
and Practices (FARMI), Food Environment
(FOODENV), Nutritional Outcomes (NUTRI),
Climate Change (CLIMA), and Food Security
(FOODSEC).
Single-item constructs with inherently negative indicators
(CLIMA: GHG emissions; FOODSEC: poverty rates)
were reversed so that higher values consistently indicate more favorable
conditions. For multi-item constructs, indicators were kept in their
original orientation, allowing the estimation procedure to determine the
direction of their contribution.
Variables were classified by type to facilitate subsequent preprocessing:
infra_1-5), ecosystems (ecosy_1-3), farming
(farmi_1-10), and nutrition (nutri_1-5), as
well as foodenv_4 and foodsec.foodenv_1-3).clima).envir_1-3).data_raw <- read_excel("basePCAcompleta.xlsx") %>%
clean_names()
data_raw <- data_raw %>%
select(
infra_1 = ig8, infra_2 = ii5, infra_3 = ii6,
infra_4 = ii10, infra_5 = d1,
envir_1 = w1, envir_2 = w2, envir_3 = o6,
ecosy_1 = ig51, ecosy_2 = ig53, ecosy_3 = ii1,
farmi_1 = ig52, farmi_2 = n1, farmi_3 = n2,
farmi_4 = pa1, farmi_5 = pa3, farmi_6 = r2,
farmi_7 = v3, farmi_8 = v4, farmi_9 = c2, farmi_10 = v6,
foodenv_1 = b3, foodenv_2 = b4, foodenv_3 = b5,
foodenv_4 = ii3,
nutri_1 = f1, nutri_2 = f2, nutri_3 = f3,
nutri_4 = h1, nutri_5 = h2,
clima = p1,
foodsec = im1) %>%
mutate(
clima = -clima,
foodsec = 1-foodsec
)
indicator_vars <- data_raw %>%
select(matches("^(infra|envir|ecosy|farmi|foodenv|nutri)_[0-9]+$"), clima, foodsec) %>%
names()
prop_vars <- indicator_vars %>%
keep(~ str_detect(.x, "^(infra|ecosy|farmi|nutri)_")) %>%
union(intersect(c("foodenv_4", "foodsec"), indicator_vars)) %>%
unique()
count_vars <- c("foodenv_1","foodenv_2","foodenv_3")
signed_vars <- c("clima")
dummy_vars <- c("envir_1","envir_2","envir_3")
Descriptive Statistics and Missing Data. Summary statistics, skewness, and kurtosis were computed for all indicators to provide an overview of their distributional properties. Histograms complement the summary tables by visualizing distributional shapes and detecting extreme deviations. These diagnostics establish a baseline understanding of the data before estimation and guide subsequent outlier treatment.
Indicators with more than 5% missing values are typically excluded,
as imputation may compromise PLS-SEM validity. In this dataset,
envir_3 (o6) (12%) and farmi_10 (v6) (10%)
exceeded this threshold and were removed. The table below reports
summary statistics, distributional shape, and missing-data percentages,
with problematic indicators highlighted in red, while the histograms
illustrate skewness and kurtosis to help detect severely distorted
variables.
desc_df <- data_raw %>%
select(all_of(indicator_vars)) %>%
pivot_longer(everything(),
names_to = "Variable",
values_to = "Value") %>%
group_by(Variable) %>%
summarize(
Min = min(Value, na.rm=TRUE),
Q1 = quantile(Value, .25, na.rm=TRUE),
Median = median(Value, na.rm=TRUE),
Mean = mean(Value, na.rm=TRUE),
Q3 = quantile(Value, .75, na.rm=TRUE),
Max = max(Value, na.rm=TRUE),
Skew = psych::skew(Value, na.rm=TRUE),
Kurt = psych::kurtosi(Value, na.rm=TRUE),
Hist_list = list(Value),
Hist = "",
Count = sum(is.na(Value)),
"%" = 100 * Count / n(),
.groups = "drop"
)%>%
mutate(Type = case_when(
Variable %in% prop_vars ~ "Proportion",
Variable %in% count_vars ~ "Count",
Variable %in% signed_vars ~ "Continuous",
Variable %in% dummy_vars ~ "Dummy",
TRUE ~ "other"))%>%
select(Variable, Type, everything())
perc_bg <- ifelse(desc_df$`%` > 5, "firebrick", "transparent")
perc_text <- ifelse(desc_df$`%` > 5, "white", "black")
kable(desc_df %>% select(-Hist_list),
caption = "<b><span style='color:black'>Descriptive Statistics and Missing Data of Indicators</span></b><br>
<span style='font-weight:normal; color:black; font-size:90%'>
Red highlighting indicates variables with more than 5% missing observations.
</span>",
digits = 2,
format = "html",
escape = FALSE,
align = c("l", rep("c", ncol(desc_df) - 1))) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
fixed_thead = TRUE,
position = "center",
full_width = FALSE
) %>%
add_header_above(c(
" " = 2,
"Descriptive Statistics" = 6,
"Distribution" =3,
"Missing Data" = 2
))%>%
column_spec(11, image = spec_hist(desc_df$Hist_list, same_lim = FALSE))%>%
column_spec(13, background = perc_bg, color = perc_text)
| Variable | Type | Min | Q1 | Median | Mean | Q3 | Max | Skew | Kurt | Hist | Count | % |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| clima | Continuous | -35247300 | -222227.25 | -92783.00 | -329749.70 | -44329.50 | 1264224.00 | -14.25 | 298.86 | 0 | 0.00 | |
| ecosy_1 | Proportion | 0 | 0.00 | 0.01 | 0.04 | 0.04 | 1.00 | 4.42 | 28.44 | 7 | 0.13 | |
| ecosy_2 | Proportion | 0 | 0.00 | 0.01 | 0.04 | 0.04 | 0.76 | 3.97 | 23.13 | 7 | 0.13 | |
| ecosy_3 | Proportion | 0 | 0.11 | 0.20 | 0.24 | 0.32 | 0.98 | 1.19 | 1.27 | 17 | 0.31 | |
| envir_1 | Dummy | 0 | 0.00 | 0.00 | 0.28 | 1.00 | 1.00 | 0.96 | -1.08 | 108 | 1.94 | |
| envir_2 | Dummy | 0 | 0.00 | 0.00 | 0.07 | 0.00 | 1.00 | 3.33 | 9.08 | 108 | 1.94 | |
| envir_3 | Dummy | 0 | 0.00 | 1.00 | 0.53 | 1.00 | 1.00 | -0.10 | -1.99 | 670 | 12.03 | |
| farmi_1 | Proportion | 0 | 0.00 | 0.01 | 0.05 | 0.06 | 1.00 | 3.19 | 13.43 | 7 | 0.13 | |
| farmi_10 | Proportion | 0 | 0.01 | 0.03 | 0.09 | 0.10 | 1.00 | 2.85 | 9.23 | 571 | 10.25 | |
| farmi_2 | Proportion | 0 | 0.08 | 0.21 | 0.34 | 0.58 | 1.00 | 0.82 | -0.75 | 14 | 0.25 | |
| farmi_3 | Proportion | 0 | 0.14 | 0.43 | 0.43 | 0.69 | 1.00 | 0.10 | -1.30 | 14 | 0.25 | |
| farmi_4 | Proportion | 0 | 0.05 | 0.14 | 0.17 | 0.26 | 0.82 | 0.92 | 0.25 | 7 | 0.13 | |
| farmi_5 | Proportion | 0 | 0.42 | 0.68 | 0.63 | 0.89 | 1.00 | -0.55 | -0.76 | 77 | 1.38 | |
| farmi_6 | Proportion | 0 | 0.16 | 0.33 | 0.36 | 0.54 | 1.00 | 0.49 | -0.74 | 56 | 1.01 | |
| farmi_7 | Proportion | 0 | 0.12 | 0.30 | 0.36 | 0.56 | 1.00 | 0.56 | -0.81 | 7 | 0.13 | |
| farmi_8 | Proportion | 0 | 0.00 | 0.00 | 0.02 | 0.02 | 0.93 | 7.62 | 94.49 | 7 | 0.13 | |
| farmi_9 | Proportion | 0 | 0.02 | 0.06 | 0.11 | 0.15 | 1.00 | 2.18 | 5.79 | 0 | 0.00 | |
| foodenv_1 | Count | 0 | 0.70 | 4.11 | 7.19 | 11.25 | 74.43 | 1.73 | 4.26 | 12 | 0.22 | |
| foodenv_2 | Count | 0 | 1.45 | 3.82 | 6.16 | 8.16 | 87.50 | 2.40 | 9.25 | 12 | 0.22 | |
| foodenv_3 | Count | 0 | 0.00 | 0.00 | 0.91 | 1.00 | 912.00 | 62.76 | 4342.62 | 7 | 0.13 | |
| foodenv_4 | Proportion | 0 | 0.53 | 0.76 | 0.71 | 0.94 | 1.00 | -0.64 | -0.51 | 258 | 4.63 | |
| foodsec | Proportion | 0 | 0.50 | 0.71 | 0.67 | 0.85 | 1.00 | -0.45 | -0.69 | 0 | 0.00 | |
| infra_1 | Proportion | 0 | 0.02 | 0.06 | 0.09 | 0.12 | 0.77 | 2.20 | 6.05 | 7 | 0.13 | |
| infra_2 | Proportion | 0 | 0.80 | 0.90 | 0.84 | 0.95 | 1.00 | -2.01 | 4.44 | 13 | 0.23 | |
| infra_3 | Proportion | 0 | 0.10 | 0.22 | 0.24 | 0.36 | 1.00 | 0.61 | -0.27 | 47 | 0.84 | |
| infra_4 | Proportion | 0 | 0.21 | 0.37 | 0.39 | 0.56 | 1.00 | 0.43 | -0.41 | 88 | 1.58 | |
| infra_5 | Proportion | 0 | 0.23 | 0.38 | 0.42 | 0.59 | 1.00 | 0.44 | -0.54 | 68 | 1.22 | |
| nutri_1 | Proportion | 0 | 0.16 | 0.26 | 0.27 | 0.37 | 0.86 | 0.44 | -0.29 | 0 | 0.00 | |
| nutri_2 | Proportion | 0 | 0.01 | 0.04 | 0.07 | 0.10 | 0.51 | 1.72 | 3.60 | 0 | 0.00 | |
| nutri_3 | Proportion | 0 | 0.06 | 0.12 | 0.14 | 0.20 | 0.77 | 1.34 | 2.83 | 0 | 0.00 | |
| nutri_4 | Proportion | 0 | 0.11 | 0.21 | 0.23 | 0.32 | 0.79 | 0.64 | -0.08 | 0 | 0.00 | |
| nutri_5 | Proportion | 0 | 0.02 | 0.05 | 0.06 | 0.08 | 0.46 | 1.74 | 4.71 | 0 | 0.00 |
raw_long <- data_raw %>%
select(all_of(indicator_vars)) %>%
pivot_longer(everything(),
names_to = "Variable",
values_to = "Value")
ggplot(raw_long, aes(x=Value)) +
geom_histogram(bins=30,
aes(fill=..count..),
color="white") +
scale_fill_viridis_c() +
facet_wrap(~ Variable,
scales = "free", ncol = 3) +
labs(title="Histograms of Raw Indicators",
x=NULL, y="Count") +
theme_minimal()
Key Points (Data Screening). Regarding the missing data,
envir_3 (o6)andfarmi_10 (v6)had 12% and 10% missing values, respectively, and were removed. All other indicators had less than 5% missing values and were retained.For the distributional diagnostics, nonnormality is considered severe whenthe absolute value of skewness exceeds 2 or when kurtosis exceeds about 8. Several indicators surpassed these thresholds, notably
clima (p1),ecosy_1-2 (ig51, ig53),envir_2 (w2)(binary, high kurtosis expected),farmi_1 (ig52),farmi_8 (v4),farmi_9 (c2),foodenv_2-3 (b4–b5), andinfra_1-2 (ig8, ii5).
Pre-estimation adjustments were implemented to address distributional challenges affecting the OLS regressions embedded in PLS-SEM. While the method is robust to nonnormality, influential outliers and heteroscedasticity may still bias inference. variance-stabilizing transformations were applied to properly identify outliers and to construct alternative estimation scenarios to assessing robustness. After the remove og the indicators due to their missingvalues, the subsequent analyses rely on the remaining 30 indicators.
data_clean <- data_raw %>% select(-envir_3, -farmi_10)
dummy_vars <- setdiff(dummy_vars, "envir_3")
prop_vars <- setdiff(prop_vars, "farmi_10")
Transformation Strategy. Transformations are used to stabilize variance (especially for bounded proportions) and to reduce tail heaviness in skewed distributions. This steps aim to reduce leverage, rather than to achieve perfect normality, and to improve comparability across measurement:
skew_lookup <- setNames(desc_df$Skew, desc_df$Variable)
prop_skew_neg <- intersect(prop_vars, names(skew_lookup[skew_lookup < 0]))
data_transformed <- data_clean %>%
mutate(
across(all_of(prop_vars),
~ if (cur_column() %in% prop_skew_neg) {
-asin(sqrt(pmax(pmin(1 - .x, 1), 0)))
} else {
asin(sqrt(pmax(pmin(.x, 1), 0)))
},
.names = "t_{.col}"),
across(all_of(count_vars), ~ log(.x + 1), .names = "t_{.col}"),
across(all_of(signed_vars), ~ sign(.x) * log(abs(.x)+1), .names = "t_{.col}")
)
t_vars <- grep("^t_", names(data_transformed), value = TRUE)
data_transformed <- data_transformed %>%
mutate(
across(all_of(t_vars),
~ (. - mean(., na.rm = TRUE)) / sd(., na.rm = TRUE),
.names = "z_{.col}"),
across(all_of(dummy_vars),
~ (. - mean(., na.rm = TRUE)) / sd(., na.rm = TRUE),
.names = "z_{.col}"))
z_vars <- grep("^z_", names(data_transformed), value = TRUE)
z_t_vars <- grep("^z_t_", names(data_transformed), value = TRUE)
Post-transform distributions. As expected, extreme values are compressed and mass is redistributed toward the center.
trans_long <- data_transformed %>%
select(all_of(t_vars)) %>%
pivot_longer(cols = everything(), names_to="Variable", values_to="Value")
ggplot(trans_long, aes(x=Value)) +
geom_histogram(bins=30, aes(fill = ..count..), color="white") +
scale_fill_viridis_c() +
facet_wrap(~Variable, scales = "free", ncol = 3) +
labs(title = "Histograms of Transformed Indicators", x = "Transformed Value", y = "Count") +
theme_minimal()
Standardized indicators. After z-standardization, all indicators share a common scale, facilitating comparison. Some residual skew may remain, which is acceptable given the nonparametric nature of PLS-SEM.
z_long <- data_transformed %>%
select(all_of(z_t_vars)) %>%
pivot_longer(cols = everything(), names_to="Variable", values_to="Value")
ggplot(z_long, aes(x=Value)) +
geom_histogram(bins=30, aes(fill = ..count..), color="white") +
scale_fill_viridis_c() +
facet_wrap(~Variable, scales = "free", ncol = 3) +
labs(title = "Histograms of Transformed & Standardized Indicators", x = "Transformed & Standardized Value", y = "Count") +
theme_minimal()
Outlier Tratment. Univariate screening was performed on standardized indicators before structural estimation. The main PLS-SEM model uses the full sample, and outlier treatments are implemented only in robustness scenarios. The boxplots of standardized indicators above highlight tails and potential extremes (points beyond whiskers). This screening was not applied to binary indicators, for which outliers are not defined.
z_long <- data_transformed %>%
select(all_of(z_t_vars)) %>%
pivot_longer(cols = everything(), names_to = "Variable", values_to = "Z")
ggplot(z_long, aes(x = Variable, y = Z)) +
geom_boxplot(outlier.colour = "firebrick", fill = "grey90", notch = TRUE) +
coord_flip() +
labs(
title = "Boxplots of Standardized Indicators",
x = NULL,
y = "Z-score") +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
axis.text.y = element_text(face = "bold"))
Although, a formal flag protocol was defined based on three rules:
For each indicator, the share of flagged cases is computed under IQR, HI, and Z4. When any rule identifies more than 5% of observations, targeted adjustments (winsorization and listwise deletion) are applied: unilateral outliers are addressed at 5th or 95th percentile, and bilateral or ambiguous extremes are symmetrically adjusted at both tails. Indicators below all thresholds remain unchanged.
flag_iqr <- function(x){
q <- quantile(x, c(.25, .75), na.rm=TRUE);
i <- diff(q)
x < (q[1] - 1.5*i) | x > (q[2] + 1.5*i)
}
flag_tail <- function(x, side=c("low","high")){
side <- match.arg(side)
q <- quantile(x, c(.25, .75), na.rm=TRUE);
i <- diff(q)
if (side == "low") x < (q[1] - 1.5*i) else x > (q[2] + 1.5*i)
}
flag_hampel <- function(x){
m <- median(x, na.rm=TRUE);
mad <- median(abs(x - m), na.rm=TRUE) * 1.4826
abs(x - m) > 3*mad
}
z_data <- select(data_transformed, all_of(z_t_vars))
iqr_p <- sapply(z_data, function(v) mean(flag_iqr(v), na.rm=TRUE) * 100)
hi_p <- sapply(z_data, function(v) mean(flag_hampel(v), na.rm=TRUE) * 100)
z4_p <- sapply(z_data, function(v) mean(abs(v)>4, na.rm=TRUE) * 100)
z3_p <- sapply(z_data, function(v) mean(abs(v)>3, na.rm=TRUE) * 100)
low_p <- sapply(z_data, function(v) mean(flag_tail(v,"low"), na.rm=TRUE) * 100)
high_p <- sapply(z_data, function(v) mean(flag_tail(v,"high"), na.rm=TRUE) * 100)
z_list <- as.list(z_data)
outlier_summary <- tibble(
Variable = names(iqr_p),
Boxplot = "",
IQR = iqr_p,
HI = hi_p,
Z4 = z4_p,
Z3 = z3_p,
`Lower` = low_p,
`Upper` = high_p) %>%
mutate(
IQR_gt5 = IQR > 5,
HI_gt5 = HI > 5,
Z4_gt5 = Z4 > 5,
Trigger = ifelse(IQR_gt5 | HI_gt5 | Z4_gt5, "Yes", "No"),
Side = case_when(
Trigger == "No" ~ "-",
`Lower` > 0 & `Upper` == 0 ~ "Low",
`Upper` > 0 & `Lower` == 0 ~ "High",
`Lower` > 0 & `Upper` > 0 ~ "Both",
TRUE ~ "Both"))
iqr_bg <- ifelse(outlier_summary$IQR > 5, "firebrick", "transparent")
iqr_text <- ifelse(outlier_summary$IQR > 5, "white", "black")
hi_bg <- ifelse(outlier_summary$HI > 5, "firebrick", "transparent")
hi_text <- ifelse(outlier_summary$HI > 5, "white", "black")
z4_bg <- ifelse(outlier_summary$Z4 > 5, "firebrick", "transparent")
z4_text <- ifelse(outlier_summary$Z4 > 5, "white", "black")
outlier_summary %>%
select(
Variable,
IQR, HI, Z4, Z3,
Trigger, Side,
Boxplot, `Lower`, `Upper`
) %>%
kable(
caption = "<b><span style='color:black'>Univariate outlier flags (% of sample size)</span></b>",
digits = 2,
format = "html",
escape = FALSE,
align = c("l", rep("c", 9))
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
fixed_thead = TRUE,
position = "center",
full_width = FALSE
) %>%
add_header_above(
c(" " = 1, "Outlier Flags (%)" = 4, "Action" = 2, "Tail-specific (%)" = 3)
) %>%
column_spec(2, background = iqr_bg, color = iqr_text) %>%
column_spec(3, background = hi_bg, color = hi_text) %>%
column_spec(4, background = z4_bg, color = z4_text) %>%
column_spec(8,image = spec_boxplot(z_list, same_lim = FALSE))
| Variable | IQR | HI | Z4 | Z3 | Trigger | Side | Boxplot | Lower | Upper |
|---|---|---|---|---|---|---|---|---|---|
| z_t_infra_1 | 2.82 | 2.26 | 0.14 | 1.08 | No |
|
0.00 | 2.82 | |
| z_t_infra_2 | 4.48 | 4.41 | 0.29 | 1.48 | No |
|
4.48 | 0.00 | |
| z_t_infra_3 | 0.09 | 0.04 | 0.02 | 0.05 | No |
|
0.00 | 0.09 | |
| z_t_infra_4 | 1.82 | 1.73 | 0.00 | 1.73 | No |
|
0.00 | 1.82 | |
| z_t_infra_5 | 5.82 | 5.18 | 0.00 | 0.00 | Yes | High | 0.00 | 5.82 | |
| z_t_ecosy_1 | 3.95 | 4.19 | 0.67 | 1.71 | No |
|
0.00 | 3.95 | |
| z_t_ecosy_2 | 3.20 | 2.28 | 0.45 | 1.56 | No |
|
0.00 | 3.20 | |
| z_t_ecosy_3 | 2.65 | 1.78 | 0.07 | 0.56 | No |
|
0.00 | 2.65 | |
| z_t_farmi_1 | 3.88 | 5.30 | 0.40 | 1.71 | Yes | High | 0.00 | 3.88 | |
| z_t_farmi_2 | 0.00 | 2.05 | 0.00 | 0.00 | No |
|
0.00 | 0.00 | |
| z_t_farmi_3 | 0.00 | 0.00 | 0.00 | 0.00 | No |
|
0.00 | 0.00 | |
| z_t_farmi_4 | 0.14 | 0.05 | 0.00 | 0.11 | No |
|
0.00 | 0.14 | |
| z_t_farmi_5 | 0.00 | 0.00 | 0.00 | 0.00 | No |
|
0.00 | 0.00 | |
| z_t_farmi_6 | 0.13 | 0.09 | 0.00 | 0.13 | No |
|
0.00 | 0.13 | |
| z_t_farmi_7 | 0.00 | 0.00 | 0.00 | 0.00 | No |
|
0.00 | 0.00 | |
| z_t_farmi_8 | 3.58 | 2.84 | 0.86 | 1.76 | No |
|
0.00 | 3.58 | |
| z_t_farmi_9 | 2.35 | 2.30 | 0.22 | 1.04 | No |
|
0.00 | 2.35 | |
| z_t_nutri_1 | 0.41 | 0.22 | 0.00 | 0.22 | No |
|
0.34 | 0.07 | |
| z_t_nutri_2 | 0.63 | 0.34 | 0.04 | 0.54 | No |
|
0.00 | 0.63 | |
| z_t_nutri_3 | 1.04 | 0.70 | 0.09 | 0.70 | No |
|
0.00 | 1.04 | |
| z_t_nutri_4 | 0.14 | 0.05 | 0.00 | 0.05 | No |
|
0.00 | 0.14 | |
| z_t_nutri_5 | 1.06 | 0.63 | 0.11 | 0.65 | No |
|
0.00 | 1.06 | |
| z_t_foodenv_4 | 0.40 | 0.00 | 0.00 | 0.40 | No |
|
0.40 | 0.00 | |
| z_t_foodsec | 0.31 | 0.31 | 0.23 | 0.34 | No |
|
0.31 | 0.00 | |
| z_t_foodenv_1 | 0.00 | 0.00 | 0.00 | 0.00 | No |
|
0.00 | 0.00 | |
| z_t_foodenv_2 | 0.02 | 0.00 | 0.00 | 0.02 | No |
|
0.00 | 0.02 | |
| z_t_foodenv_3 | 1.74 | 31.89 | 0.95 | 1.51 | Yes | High | 0.00 | 1.74 | |
| z_t_clima | 2.53 | 1.69 | 0.20 | 0.31 | No |
|
2.24 | 0.29 |
Three indicators exceed the 5% cutoff in right-tail diagnostics:
z_t_infra_5 (d1), z_t_farmi_1 (ig52), and
z_t_foodenv_3 (b5). As these were unilateral outliers
(right tails), two robustness scenarios were introduced: Scenario A
applies winsorization at the 95th percentile, while
Scenario B removes cases at or above the same cutoff.
This yielded three datasets, enabling sensitivity analyses of outlier
handling while preserving an identical model structure across
scenarios.
Main PLS-SEM Estimation. The baseline specification relies on the complete post-screening dataset (N = 5,570; 30 indicators). Transformed variables are standardized, with no winsorization or deletion, thereby preserving the full distributional variation.
data_main <- select(data_transformed, all_of(z_vars))
names(data_main) <- gsub("^z_t_|^z_", "", names(data_main))
data_main <- data_main[, sort(names(data_main))]
Scenario A: Winsorization. This minimally invasive robustness check caps values above the 95th percentile for three flagged indicators, preserving the full sample (N = 5,570; 30 indicators). Winsorization reduces the impact of extreme values while retaining all observations.
data_winsorize <- data_transformed %>%
select(all_of(z_vars)) %>%
mutate(
w_z_t_infra_5 = Winsorize(z_t_infra_5, val = quantile(z_t_infra_5, probs = c(0, 0.95), na.rm = TRUE)),
w_z_t_farmi_1 = Winsorize(z_t_farmi_1, val = quantile(z_t_farmi_1, probs = c(0, 0.95), na.rm = TRUE)),
w_z_t_foodenv_3 = Winsorize(z_t_foodenv_3, val = quantile(z_t_foodenv_3, probs = c(0, 0.95), na.rm = TRUE))) %>%
select(-c(z_t_infra_5, z_t_farmi_1, z_t_foodenv_3))
w_vars <- grep("^w_", names(data_winsorize), value = TRUE)
w_long <- data_winsorize %>%
select(all_of(w_vars)) %>%
pivot_longer(cols = everything(), names_to = "Variable", values_to = "Z")
ggplot(w_long, aes(x = Variable, y = Z)) +
geom_boxplot(outlier.colour = "firebrick", fill = "grey90", notch = TRUE) +
coord_flip() +
labs(
title = "Boxplot of Winsorized Indicators",
x = NULL,
y = "Z-score") +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
axis.text.y = element_text(face = "bold"))
names(data_winsorize) <- gsub("^z_t_|^z_|^w_z_t_", "", names(data_winsorize))
data_winsorize <- data_winsorize[, sort(names(data_winsorize))]
Scenario B: Listwise Deletion. This conservative robustness check excludes all rows with any flagged indicator at or above the 95th-percentile cutoff, reducing sample size but removing extreme-value influence (N = 4,641; 30 indicators). Deletion serves as a stricter remedy when outliers risk distorting estimation results.
The diagnostics table above summarizes removed cases by indicator and overall, and the boxplot displays the retained values after deletion.
data_deletion <- select(data_transformed, all_of(z_vars))
flagged_indicators <- c("z_t_infra_5", "z_t_farmi_1", "z_t_foodenv_3")
stopifnot(exists("flagged_indicators"))
use_flagged <- intersect(flagged_indicators, names(data_deletion))
stopifnot(length(use_flagged) > 0)
q95 <- vapply(
data_deletion[use_flagged],
function(x) quantile(x, probs = 0.95, na.rm = TRUE, type = 8),
numeric(1))
extreme_row <- Reduce(`|`,
Map(function(col, thr) {
v <- data_deletion[[col]] >= thr
v[is.na(v)] <- FALSE
v
}, use_flagged, q95))
n_before <- nrow(data_deletion)
n_drop <- sum(extreme_row, na.rm = TRUE)
n_after <- n_before - n_drop
per_indicator_removed <- vapply(
use_flagged,
function(col) sum(data_transformed[[col]] >= q95[[col]], na.rm = TRUE),
numeric(1))
diagnostics <- data.frame(
indicator = use_flagged,
p95_cutoff = q95[use_flagged],
n_removed = per_indicator_removed,
stringsAsFactors = FALSE)
data_deletion <- data_deletion[!extreme_row, , drop = FALSE]
overall_row <- data.frame(
Indicator = "Overall (any flagged indicator ≥ p95)",
`p95 Cutoff` = NA_real_,
`Removed (n)` = n_drop,
`Removed (%)` = round(100 * n_drop / n_before, 2),
`N Before` = n_before,
`N After` = n_after,
check.names = FALSE)
per_rows <- data.frame(
Indicator = diagnostics$indicator,
`p95 Cutoff` = as.numeric(diagnostics$p95_cutoff),
`Removed (n)` = as.integer(diagnostics$n_removed),
`Removed (%)` = round(100 * diagnostics$n_removed / n_before, 2),
`N Before` = NA_integer_,
`N After` = NA_integer_,
check.names = FALSE)
deletion_report <- rbind(overall_row, per_rows) %>%
mutate(`p95 Cutoff` = ifelse(is.na(`p95 Cutoff`),NA,round(as.numeric(`p95 Cutoff`), 3)))%>%
mutate(across(everything(),~ ifelse(is.na(.x), "-", .x)))
kable(deletion_report,
format = "html",
digits = 3,
align = c("l", rep("c", 5)),
caption = "<b><span style='color:black'>Scenario B: Listwise deletion diagnostics (95th percentile rule)</span></b>",
escape = FALSE) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center",
fixed_thead = TRUE) %>%
add_header_above(
c(" " = 1, "Deletion threshold" = 1, "Removed" = 2, "Sample size" = 2)) %>%
row_spec(1, bold = TRUE)
| Indicator | p95 Cutoff | Removed (n) | Removed (%) | N Before | N After |
|---|---|---|---|---|---|
| Overall (any flagged indicator ≥ p95) |
|
929 | 16.68 | 5570 | 4641 |
| z_t_infra_5 | 2.326 | 278 | 4.99 |
|
|
| z_t_farmi_1 | 2.036 | 278 | 4.99 |
|
|
| z_t_foodenv_3 | 1.567 | 436 | 7.83 |
|
|
d_long <- data_deletion %>%
select(all_of(flagged_indicators)) %>%
pivot_longer(cols = everything(), names_to = "Variable", values_to = "Z")
ggplot(d_long, aes(x = Variable, y = Z)) +
geom_boxplot(outlier.colour = "firebrick", fill = "grey90", notch = TRUE) +
coord_flip() +
labs(
title = "Boxplot of flagged indicators (after listwise deletion)",
x = NULL,
y = "Z-score") +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
axis.text.y = element_text(face = "bold"))
names(data_deletion) <- gsub("^z_t_|^z_|^w_z_t_", "", names(data_deletion))
data_deletion <- data_deletion[, sort(names(data_deletion))]
Key Points (Data Refinement and Robustness Scenarios). After excluding
envir_3 (o6)andfarmi_10 (v6)due to excess missing values, the analyses rely on 30 indicators. Variance-stabilizing transformations were applied to reduce skewness and stabilize variance, while binary items were retained as coded. All variables were standardized to z-scores for comparability. Outlier screening based on IQR, Hampel, and Z-score rules flagged three variables above the 5% cutoff in the right tail:z_t_infra_5 (d1),z_t_farmi_1 (ig52), andz_t_foodenv_3 (b5).To assess robustness, three estimation datasets were constructed:
- Main PLS-SEM: full sample with standardized indicators, no outlier adjustments (N = 5,570).
- Scenario A (Winsorization): caps flagged values at the 95th percentile, preserving N = 5,570.
- Scenario B (Deletion): removes observations with any flagged indicator at or above the 95th percentile, reducing the sample to N = 4,641.
All scenarios retain the same 30 indicators and identical model structure, enabling assessment of robustness of structural estimates to alternative outlier treatments.
The analysis employs variance-based structural equation modeling (PLS-SEM), with both measurement and structural components explicitly specified. Formative constructs are estimated using regression weights, in line with recommendations for indicators that represent distinct facets rather than interchangeable reflections.
# Customize SEMinR diagram theme
theme <- seminr_theme_get()
theme$sm.edge.label.show <- TRUE
theme$sm.edge.boot.show_t_value <- TRUE
theme$sm.edge.boot.show_p_value <- TRUE
theme$sm.edge.boot.show_p_stars <- TRUE
theme$mm.edge.label.show <- TRUE
theme$mm.edge.boot.show_p_value <- TRUE
theme$mm.edge.boot.show_p_stars <- TRUE
theme$sm.edge.positive.color <- "steelblue"
theme$sm.edge.negative.color <- "firebrick"
theme$construct.compositeA.arrow <- "none"
seminr_theme_set(theme)
Measurement model. Latent constructs and their
indicators are defined with the constructs() function from
the seminr package, all specified as composites with
Mode B weights.
model_constructs <- constructs(
composite("CLIMA", single_item("clima")),
composite("ECOSY", multi_items("ecosy_", 1:3), weights = mode_B),
composite("ENVIR", multi_items("envir_", 1:2), weights = mode_B),
composite("FARMI", multi_items("farmi_", 1:9), weights = mode_B),
composite("FOODENV", multi_items("foodenv_", 1:4), weights = mode_B),
composite("FOODSEC", single_item("foodsec")),
composite("INFRA", multi_items("infra_", 1:5), weights = mode_B),
composite("NUTRI", multi_items("nutri_", 1:5), weights = mode_B)
)
plot(model_constructs, title = "Measurement model specification")
Structural Model. Directional relationships among
constructs are specified with the relationships()
function.
model_paths <- relationships(
paths(from = c("ENVIR"), to = c("INFRA","ECOSY","FARMI","FOODENV")),
paths(from = c("INFRA"), to = c("ECOSY","FARMI","FOODENV")),
paths(from = c("ECOSY"), to = c("FARMI","CLIMA")),
paths(from = c("FARMI"), to = c("FOODENV","NUTRI","CLIMA","FOODSEC")),
paths(from = c("FOODENV"), to = c("NUTRI","CLIMA","FOODSEC"))
)
plot(model_paths, title = "Structural model specification")
Model Estimation. The PLS path model is estimated
with the estimate_pls() function for the main dataset and
the two robustness scenarios (A: winsorization; B: listwise deletion).
Inner weights follow the path weighting scheme, and missing data are
handled by mean replacement.
model_pls_main <- estimate_pls(
data = data_main,
measurement_model = model_constructs,
structural_model = model_paths,
inner_weights = path_weighting,
missing = mean_replacement)
model_pls_scenarioA <- estimate_pls(
data = data_winsorize,
measurement_model = model_constructs,
structural_model = model_paths,
inner_weights = path_weighting,
missing = mean_replacement)
model_pls_scenarioB <- estimate_pls(
data = data_deletion,
measurement_model = model_constructs,
structural_model = model_paths,
inner_weights = path_weighting,
missing = mean_replacement)
s_main <- summary(model_pls_main)
s_A <- summary(model_pls_scenarioA)
s_B <- summary(model_pls_scenarioB)
Formative measurement models are evaluated in terms of multicollinearity and the significance and relevance of indicator weights and loadings, rather than internal consistency (Cronbach’s alpha, rhoA, CR) or convergent validity (AVE). Results are reported for the main estimation (full standardized dataset) and for robustness checks (Scenario A: winsorization at the top 5%; Scenario B: listwise deletion of flagged outliers).
add_pval <- function(df_stats, data_model) {
df <- as.data.frame(df_stats, stringsAsFactors = FALSE)
t_col <- grep("T Stat\\.", names(df), ignore.case = TRUE, value = TRUE)[1]
if (is.null(t_col)) stop("T-stat not found.")
df_model <- nrow(data_model)
df %>%
select(-matches("^0\\.5% CI|99\\.5% CI$")) %>%
mutate(`p-value` = ifelse(
is.na(.data[[t_col]]), NA_real_,
round(2 * pt(abs(.data[[t_col]]), df = df_model, lower.tail = FALSE), 3)))
}
format_vif_cells <- function(x, thr = 5, digits = 3) {
out <- ifelse(is.na(x), "", sprintf(paste0("%.", digits, "f"), x))
bold_idx <- !is.na(x) & x >= thr
out[bold_idx] <- cell_spec(out[bold_idx], bold = TRUE)
out
}
kable_group_by_construct <- function(df_fmt, caption, scen_cols) {
idx <- df_fmt %>%
mutate(row_id = row_number()) %>%
group_by(Construct) %>%
summarise(start = min(row_id), end = max(row_id), .groups = "drop")
kb <- kable(df_fmt %>% select(-Construct),
format = "html", escape = FALSE,
align = c("l", rep("c", length(scen_cols))),
caption = caption, col.names = c("Indicator", scen_cols)) %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE, position = "center", fixed_thead = TRUE) %>%
add_header_above(c(" " = 1, "Scenarios" = length(scen_cols)))
if (nrow(idx) > 0) for (i in seq_len(nrow(idx))) {
kb <- kb %>% group_rows(idx$Construct[i], idx$start[i], idx$end[i])}
kb
}
print_boot_tbl <- function(boot_list, caption){
boot_results_all <- map_dfr(names(boot_list), ~{
boot_list[[.x]] %>%
rownames_to_column("Indicator") %>%
mutate(Scenario = .x)
})
idx <- boot_results_all %>% mutate(row_id = row_number()) %>%
group_by(Scenario) %>% summarise(start = min(row_id), end = max(row_id), .groups = "drop")
boot_results_all <- boot_results_all %>%
mutate(signif = case_when(
`p-value` < 0.01 ~ "<sup>***</sup>",
`p-value` < 0.05 ~ "<sup>**</sup>",
`p-value` < 0.1 ~ "<sup>*</sup>",
TRUE ~ ""),
`Original Est.` = paste0(round(`Original Est.`,3), signif))
kb <- kable(boot_results_all %>% select(-c(Scenario, signif)),
caption = caption, digits = 3, format = "html", escape = FALSE, booktabs = TRUE,
align = c("l", rep("c", 5))) %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE, position = "center", fixed_thead = TRUE)
if (nrow(idx) > 0) for(i in seq_len(nrow(idx))){
kb <- kb %>% group_rows(idx$Scenario[i], idx$start[i], idx$end[i], bold = TRUE)}
kb
}
Collinearity assessment (VIF). The baseline VIF
evaluation indicated critical collinearity (\(VIF > 5\)) for
nutri_3 (f3), nutri_4 (h1), and
nutri_5 (h2), with cautionary values (between \(3\) and \(5\)) for nutri_2 (f2),
farmi_2 (n1), and farmi_3 (n2). Non-critical
indicators were retained, while iterative refinements were performed to
address the critical cases:
nutri_3 (f3)
excluded.nutri_3 (f3) and
nutri_5 (h2) excluded.After these adjustments, all remaining indicators had VIF values below the critical threshold, confirming the absence of multicollinearity.
vif_baseline <- list(
"Main PLS-SEM" = s_main$validity$vif_items,
"Scenario A" = s_A$validity$vif_items,
"Scenario B" = s_B$validity$vif_items)
drop_constructs <- c("CLIMA","FOODSEC")
vif_iter0 <- imap_dfr(
vif_baseline,
function(vif_list, sc_name){
valid_cons <- setdiff(names(vif_list), drop_constructs)
imap_dfr(vif_list[valid_cons], function(vec, cn){
tibble(
Scenario = sc_name,
Construct = cn,
Indicator = names(vec),
VIF = as.numeric(vec))})}) %>%
filter(!is.na(VIF), is.finite(VIF)) %>%
mutate(Scenario = factor(Scenario, levels = c("Main PLS-SEM","Scenario A","Scenario B"))) %>%
arrange(Construct, Indicator, Scenario) %>%
select(Construct, Indicator, Scenario, VIF) %>%
pivot_wider(names_from = Scenario, values_from = VIF) %>%
arrange(Construct, Indicator)
scen_cols0 <- setdiff(names(vif_iter0), c("Construct","Indicator"))
vif_fmt0 <- vif_iter0
vif_fmt0[scen_cols0] <- lapply(vif_fmt0[scen_cols0], format_vif_cells)
kable_group_by_construct(
vif_fmt0,
paste0(
"<b><span style='color:black'>Item-level VIF values by scenario (formative indicators)</span></b><br>",
"<span style='font-size:90%;color:gray'>Iteration 0: Baseline.</span>"),
scen_cols0
)
| Indicator | Main PLS-SEM | Scenario A | Scenario B |
|---|---|---|---|
| ECOSY | |||
| ecosy_1 | 2.955 | 2.955 | 2.753 |
| ecosy_2 | 2.948 | 2.948 | 2.747 |
| ecosy_3 | 1.004 | 1.004 | 1.004 |
| ENVIR | |||
| envir_1 | 1.188 | 1.188 | 1.184 |
| envir_2 | 1.188 | 1.188 | 1.184 |
| FARMI | |||
| farmi_1 | 1.450 | 1.536 | 1.517 |
| farmi_2 | 4.607 | 4.636 | 4.661 |
| farmi_3 | 3.886 | 3.891 | 4.010 |
| farmi_4 | 1.340 | 1.346 | 1.278 |
| farmi_5 | 1.325 | 1.327 | 1.345 |
| farmi_6 | 1.358 | 1.377 | 1.399 |
| farmi_7 | 1.839 | 1.843 | 1.723 |
| farmi_8 | 1.070 | 1.075 | 1.071 |
| farmi_9 | 1.134 | 1.135 | 1.115 |
| FOODENV | |||
| foodenv_1 | 1.183 | 1.180 | 1.170 |
| foodenv_2 | 1.003 | 1.003 | 1.003 |
| foodenv_3 | 1.019 | 1.008 | 1.001 |
| foodenv_4 | 1.187 | 1.182 | 1.167 |
| INFRA | |||
| infra_1 | 1.280 | 1.280 | 1.243 |
| infra_2 | 1.143 | 1.143 | 1.152 |
| infra_3 | 1.252 | 1.252 | 1.220 |
| infra_4 | 1.115 | 1.115 | 1.114 |
| infra_5 | 1.069 | 1.069 | 1.051 |
| NUTRI | |||
| nutri_1 | 2.895 | 2.895 | 2.923 |
| nutri_2 | 3.924 | 3.924 | 3.812 |
| nutri_3 | 10.372 | 10.372 | 10.434 |
| nutri_4 | 6.260 | 6.260 | 6.470 |
| nutri_5 | 9.838 | 9.838 | 9.706 |
model_constructs_iter1 <- constructs(
composite("CLIMA", single_item("clima")),
composite("ECOSY", multi_items("ecosy_", 1:3), weights = mode_B),
composite("ENVIR", multi_items("envir_", 1:2), weights = mode_B),
composite("FARMI", multi_items("farmi_", 1:9), weights = mode_B),
composite("FOODENV", multi_items("foodenv_", 1:4), weights = mode_B),
composite("FOODSEC", single_item("foodsec")),
composite("INFRA", multi_items("infra_", 1:5), weights = mode_B),
composite("NUTRI", multi_items("nutri_", c(1,2,4,5)), weights = mode_B))
model_pls_iter1 <- list(
"Main" = estimate_pls(data_main, model_constructs_iter1, structural_model = model_paths, inner_weights = path_weighting, missing = mean_replacement),
"ScenarioA" = estimate_pls(data_winsorize, model_constructs_iter1, structural_model = model_paths, inner_weights = path_weighting, missing = mean_replacement),
"ScenarioB" = estimate_pls(data_deletion, model_constructs_iter1, structural_model = model_paths, inner_weights = path_weighting, missing = mean_replacement))
s_main_iter1 <- summary(model_pls_iter1$Main)
s_A_iter1 <- summary(model_pls_iter1$ScenarioA)
s_B_iter1 <- summary(model_pls_iter1$ScenarioB)
vif_iter1 <- list(
"Main PLS-SEM" = s_main_iter1$validity$vif_items,
"Scenario A" = s_A_iter1$validity$vif_items,
"Scenario B" = s_B_iter1$validity$vif_items)
vif_iter1 <- imap_dfr(
vif_iter1,
function(vif_list, sc_name){
valid_cons <- setdiff(names(vif_list), drop_constructs)
imap_dfr(vif_list[valid_cons], function(vec, cn){
tibble(
Scenario = sc_name,
Construct = cn,
Indicator = names(vec),
VIF = as.numeric(vec))})}) %>%
filter(!is.na(VIF), is.finite(VIF)) %>%
mutate(Scenario = factor(Scenario, levels = c("Main PLS-SEM","Scenario A","Scenario B"))) %>%
arrange(Construct, Indicator, Scenario) %>%
select(Construct, Indicator, Scenario, VIF) %>%
pivot_wider(names_from = Scenario, values_from = VIF) %>%
arrange(Construct, Indicator)
scen_cols1 <- setdiff(names(vif_iter1), c("Construct","Indicator"))
vif_fmt1 <- vif_iter1
vif_fmt1[scen_cols1] <- lapply(vif_fmt1[scen_cols1], format_vif_cells)
kable_group_by_construct(
vif_fmt1,
paste0(
"<b><span style='color:black'>Item-level VIF values by scenario (formative indicators)</span></b><br>",
"<span style='font-size:90%;color:gray'>Iteration 1: Exclude nutri_3.</span>"),
scen_cols1)
| Indicator | Main PLS-SEM | Scenario A | Scenario B |
|---|---|---|---|
| ECOSY | |||
| ecosy_1 | 2.955 | 2.955 | 2.753 |
| ecosy_2 | 2.948 | 2.948 | 2.747 |
| ecosy_3 | 1.004 | 1.004 | 1.004 |
| ENVIR | |||
| envir_1 | 1.188 | 1.188 | 1.184 |
| envir_2 | 1.188 | 1.188 | 1.184 |
| FARMI | |||
| farmi_1 | 1.450 | 1.536 | 1.517 |
| farmi_2 | 4.607 | 4.636 | 4.661 |
| farmi_3 | 3.886 | 3.891 | 4.010 |
| farmi_4 | 1.340 | 1.346 | 1.278 |
| farmi_5 | 1.325 | 1.327 | 1.345 |
| farmi_6 | 1.358 | 1.377 | 1.399 |
| farmi_7 | 1.839 | 1.843 | 1.723 |
| farmi_8 | 1.070 | 1.075 | 1.071 |
| farmi_9 | 1.134 | 1.135 | 1.115 |
| FOODENV | |||
| foodenv_1 | 1.183 | 1.180 | 1.170 |
| foodenv_2 | 1.003 | 1.003 | 1.003 |
| foodenv_3 | 1.019 | 1.008 | 1.001 |
| foodenv_4 | 1.187 | 1.182 | 1.167 |
| INFRA | |||
| infra_1 | 1.280 | 1.280 | 1.243 |
| infra_2 | 1.143 | 1.143 | 1.152 |
| infra_3 | 1.252 | 1.252 | 1.220 |
| infra_4 | 1.115 | 1.115 | 1.114 |
| infra_5 | 1.069 | 1.069 | 1.051 |
| NUTRI | |||
| nutri_1 | 2.843 | 2.843 | 2.861 |
| nutri_2 | 3.889 | 3.889 | 3.779 |
| nutri_4 | 3.668 | 3.668 | 3.779 |
| nutri_5 | 5.646 | 5.646 | 5.551 |
model_constructs_iter2 <- constructs(
composite("CLIMA", single_item("clima")),
composite("ECOSY", multi_items("ecosy_", 1:3), weights = mode_B),
composite("ENVIR", multi_items("envir_", 1:2), weights = mode_B),
composite("FARMI", multi_items("farmi_", 1:9), weights = mode_B),
composite("FOODENV", multi_items("foodenv_", 1:4), weights = mode_B),
composite("FOODSEC", single_item("foodsec")),
composite("INFRA", multi_items("infra_", 1:5), weights = mode_B),
composite("NUTRI", multi_items("nutri_", c(1,2,4)), weights = mode_B))
model_pls_iter2 <- list(
"Main" = estimate_pls(data_main, model_constructs_iter2, structural_model = model_paths, inner_weights = path_weighting, missing = mean_replacement),
"ScenarioA" = estimate_pls(data_winsorize, model_constructs_iter2, structural_model = model_paths, inner_weights = path_weighting, missing = mean_replacement),
"ScenarioB" = estimate_pls(data_deletion, model_constructs_iter2, structural_model = model_paths, inner_weights = path_weighting, missing = mean_replacement))
s_main_iter2 <- summary(model_pls_iter2$Main)
s_A_iter2 <- summary(model_pls_iter2$ScenarioA)
s_B_iter2 <- summary(model_pls_iter2$ScenarioB)
vif_iter2 <- list(
"Main PLS-SEM" = s_main_iter2$validity$vif_items,
"Scenario A" = s_A_iter2$validity$vif_items,
"Scenario B" = s_B_iter2$validity$vif_items)
vif_iter2 <- imap_dfr(
vif_iter2,
function(vif_list, sc_name){
valid_cons <- setdiff(names(vif_list), drop_constructs)
imap_dfr(vif_list[valid_cons], function(vec, cn){
tibble(
Scenario = sc_name,
Construct = cn,
Indicator = names(vec),
VIF = as.numeric(vec))})}) %>%
filter(!is.na(VIF), is.finite(VIF)) %>%
mutate(Scenario = factor(Scenario, levels = c("Main PLS-SEM","Scenario A","Scenario B"))) %>%
arrange(Construct, Indicator, Scenario) %>%
select(Construct, Indicator, Scenario, VIF) %>%
pivot_wider(names_from = Scenario, values_from = VIF) %>%
arrange(Construct, Indicator)
scen_cols2 <- setdiff(names(vif_iter2), c("Construct","Indicator"))
vif_fmt2 <- vif_iter2
vif_fmt2[scen_cols2] <- lapply(vif_fmt2[scen_cols2], format_vif_cells)
kable_group_by_construct(
vif_fmt2,
paste0(
"<b><span style='color:black'>Item-level VIF values by scenario (formative indicators)</span></b><br>",
"<span style='font-size:90%;color:gray'>Iteration 2: Exclude nutri_3 & nutri_5.</span>"),
scen_cols2)
| Indicator | Main PLS-SEM | Scenario A | Scenario B |
|---|---|---|---|
| ECOSY | |||
| ecosy_1 | 2.955 | 2.955 | 2.753 |
| ecosy_2 | 2.948 | 2.948 | 2.747 |
| ecosy_3 | 1.004 | 1.004 | 1.004 |
| ENVIR | |||
| envir_1 | 1.188 | 1.188 | 1.184 |
| envir_2 | 1.188 | 1.188 | 1.184 |
| FARMI | |||
| farmi_1 | 1.450 | 1.536 | 1.517 |
| farmi_2 | 4.607 | 4.636 | 4.661 |
| farmi_3 | 3.886 | 3.891 | 4.010 |
| farmi_4 | 1.340 | 1.346 | 1.278 |
| farmi_5 | 1.325 | 1.327 | 1.345 |
| farmi_6 | 1.358 | 1.377 | 1.399 |
| farmi_7 | 1.839 | 1.843 | 1.723 |
| farmi_8 | 1.070 | 1.075 | 1.071 |
| farmi_9 | 1.134 | 1.135 | 1.115 |
| FOODENV | |||
| foodenv_1 | 1.183 | 1.180 | 1.170 |
| foodenv_2 | 1.003 | 1.003 | 1.003 |
| foodenv_3 | 1.019 | 1.008 | 1.001 |
| foodenv_4 | 1.187 | 1.182 | 1.167 |
| INFRA | |||
| infra_1 | 1.280 | 1.280 | 1.243 |
| infra_2 | 1.143 | 1.143 | 1.152 |
| infra_3 | 1.252 | 1.252 | 1.220 |
| infra_4 | 1.115 | 1.115 | 1.114 |
| infra_5 | 1.069 | 1.069 | 1.051 |
| NUTRI | |||
| nutri_1 | 2.842 | 2.842 | 2.861 |
| nutri_2 | 1.329 | 1.329 | 1.317 |
| nutri_4 | 2.986 | 2.986 | 3.030 |
Subsequent analyses are performed on the Refined Model, excluding indicators with critical multicollinearity. The Full Model, including all 30 indicators, was also evaluated to verify the validity of the results, given the theoretical importance of those indicators.
Indicator weights and loadings. Bootstrapped weights and loadings (6,000 resamples) were used to assess significance across scenarios. Following Hair et al. (2021, Fig. 5.2), indicators with significant weights were retained. Non-significant weights were then evaluated by loadings: items with loadings of 0.50 or higher were retained (regardless of significance); items with non-signigicant loadings below 0.50 were candidates for exclusion. Consistent with Hair et al. (2019, 2021), theoretical and content validy was also considered, since formative indicatiors are not interchangeable and their removal may compromise construct validity.
Across models (Refined, Full, and robustness scenarios), three
indicators showed non-significant weights: ecosy_3 (ii1),
envir_2 (w2) and farmi_4 (pa1). In addition,
foodenv_3 (b5) was non-significant in the main
specification, and envir_1 (w1) was flagged in Scenario B.
Indicators envir_1 (w1), envir_2 (w2) and
foodenv_3 (b5) were retained given their loadings exceeded
0.50, while farmi_4 (pa1) was kept due to significant
loading. Although ecosy_3 (ii1) had negligible empirical
contribution, it captures a distinct dimension of ecosystem
conservation. To preserve content validity, it was retained in both the
Refined and Full Models.
The table below summarize these decisions, with full bootstrap results reported subsequently.
| Indicator | Weight | Loading | Decision |
|---|---|---|---|
ecosy_3 (ii1) |
Non-significant (all scenarios) | Low (<0.03, non-significant) | Retained (content validity despite negligible empirical contribution) |
envir_1 (w1) |
Mixed: significant in Main/A, non-significant in B | High (0.7–0.8, significant) | Retained (significant loading) |
envir_2 (w2) |
Non-significant (all scenarios) | High (0.7–0.9, significant) | Retained (significant loading) |
farmi_4 (pa1) |
Non-significant (all scenarios) | Moderate (0.3–0.4, significant) | Retained (significant loading) |
foodenv_3 (b5) |
Non-significant (Main only) | Low (0.09, significant) | Retained (significant loading) |
# Refined Model (after VIF exclusion)
boot_model_refined <- list(
"Main PLS-SEM" = bootstrap_model(seminr_model = model_pls_iter2$Main, nboot = 6000, seed = 35),
"Scenario A" = bootstrap_model(seminr_model = model_pls_iter2$ScenarioA, nboot = 6000, seed = 35),
"Scenario B" = bootstrap_model(seminr_model = model_pls_iter2$ScenarioB, nboot = 6000, seed = 35))
s_boot_refined <- list(
"Main PLS-SEM" = summary(boot_model_refined$`Main PLS-SEM`, alpha = 0.01),
"Scenario A" = summary(boot_model_refined$`Scenario A`, alpha = 0.01),
"Scenario B" = summary(boot_model_refined$`Scenario B`, alpha = 0.01))
# Full Model (all 30 indicators)
boot_model_full <- list(
"Main PLS-SEM" = bootstrap_model(seminr_model = model_pls_main, nboot = 6000, seed = 35),
"Scenario A" = bootstrap_model(seminr_model = model_pls_scenarioA, nboot = 6000, seed = 35),
"Scenario B" = bootstrap_model(seminr_model = model_pls_scenarioB, nboot = 6000, seed = 35))
s_boot_full <- list(
"Main PLS-SEM" = summary(boot_model_full$`Main PLS-SEM`, alpha = 0.01),
"Scenario A" = summary(boot_model_full$`Scenario A`, alpha = 0.01),
"Scenario B" = summary(boot_model_full$`Scenario B`, alpha = 0.01))
boot_results_refined_weights <- list(
"Main PLS-SEM" = add_pval(s_boot_refined$`Main PLS-SEM`$bootstrapped_weights, data_main),
"Scenario A" = add_pval(s_boot_refined$`Scenario A`$bootstrapped_weights, data_winsorize),
"Scenario B" = add_pval(s_boot_refined$`Scenario B`$bootstrapped_weights, data_deletion)
)
boot_results_refined_loadings <- list(
"Main PLS-SEM" = add_pval(s_boot_refined$`Main PLS-SEM`$bootstrapped_loadings, data_main),
"Scenario A" = add_pval(s_boot_refined$`Scenario A`$bootstrapped_loadings, data_winsorize),
"Scenario B" = add_pval(s_boot_refined$`Scenario B`$bootstrapped_loadings, data_deletion)
)
print_boot_tbl(boot_results_refined_weights,
paste0("<b><span style='color:black'>Bootstrapped Indicator Weights (Refined Model)</span></b><br>",
"<span style='font-size:90%;color:gray'>Significance levels are denoted as follows: ***p < 0.01, **p < 0.05, *p < 0.10.</span>"))
| Indicator | Original Est. | Bootstrap Mean | Bootstrap SD | T Stat. | p-value |
|---|---|---|---|---|---|
| Main PLS-SEM | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.53*** | 0.531 | 0.035 | 15.185 | 0.000 |
| ecosy_2 -> ECOSY | 0.521*** | 0.520 | 0.035 | 14.852 | 0.000 |
| ecosy_3 -> ECOSY | 0.024 | 0.024 | 0.019 | 1.312 | 0.190 |
| envir_1 -> ENVIR | 0.757** | 0.689 | 0.342 | 2.212 | 0.027 |
| envir_2 -> ENVIR | 0.418 | 0.366 | 0.408 | 1.026 | 0.305 |
| farmi_1 -> FARMI | 0.426*** | 0.425 | 0.017 | 25.719 | 0.000 |
| farmi_2 -> FARMI | -0.635*** | -0.636 | 0.030 | -21.218 | 0.000 |
| farmi_3 -> FARMI | -0.489*** | -0.489 | 0.027 | -17.933 | 0.000 |
| farmi_4 -> FARMI | 0.01 | 0.009 | 0.013 | 0.723 | 0.470 |
| farmi_5 -> FARMI | 0.172*** | 0.172 | 0.014 | 12.299 | 0.000 |
| farmi_6 -> FARMI | -0.194*** | -0.194 | 0.014 | -13.463 | 0.000 |
| farmi_7 -> FARMI | 0.24*** | 0.240 | 0.017 | 14.038 | 0.000 |
| farmi_8 -> FARMI | 0.194*** | 0.195 | 0.013 | 15.227 | 0.000 |
| farmi_9 -> FARMI | 0.153*** | 0.153 | 0.013 | 11.948 | 0.000 |
| foodenv_1 -> FOODENV | 0.927*** | 0.927 | 0.008 | 110.920 | 0.000 |
| foodenv_2 -> FOODENV | -0.105*** | -0.104 | 0.015 | -6.939 | 0.000 |
| foodenv_3 -> FOODENV | -0.014 | -0.016 | 0.013 | -1.057 | 0.291 |
| foodenv_4 -> FOODENV | 0.162*** | 0.162 | 0.015 | 10.582 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.242*** | 0.241 | 0.023 | 10.374 | 0.000 |
| infra_2 -> INFRA | 0.186*** | 0.185 | 0.020 | 9.094 | 0.000 |
| infra_3 -> INFRA | 0.289*** | 0.289 | 0.021 | 13.632 | 0.000 |
| infra_4 -> INFRA | 0.683*** | 0.684 | 0.018 | 38.851 | 0.000 |
| infra_5 -> INFRA | 0.08*** | 0.080 | 0.020 | 4.072 | 0.000 |
| nutri_1 -> NUTRI | -0.277*** | -0.276 | 0.057 | -4.819 | 0.000 |
| nutri_2 -> NUTRI | -0.1*** | -0.100 | 0.037 | -2.710 | 0.007 |
| nutri_4 -> NUTRI | 1.252*** | 1.251 | 0.042 | 29.702 | 0.000 |
| Scenario A | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.517*** | 0.518 | 0.036 | 14.240 | 0.000 |
| ecosy_2 -> ECOSY | 0.535*** | 0.533 | 0.037 | 14.468 | 0.000 |
| ecosy_3 -> ECOSY | 0.028 | 0.028 | 0.018 | 1.559 | 0.119 |
| envir_1 -> ENVIR | 0.73** | 0.662 | 0.364 | 2.004 | 0.045 |
| envir_2 -> ENVIR | 0.452 | 0.379 | 0.434 | 1.041 | 0.298 |
| farmi_1 -> FARMI | 0.465*** | 0.465 | 0.016 | 28.886 | 0.000 |
| farmi_2 -> FARMI | -0.609*** | -0.609 | 0.029 | -21.123 | 0.000 |
| farmi_3 -> FARMI | -0.474*** | -0.474 | 0.026 | -18.140 | 0.000 |
| farmi_4 -> FARMI | -0.002 | -0.002 | 0.013 | -0.162 | 0.871 |
| farmi_5 -> FARMI | 0.163*** | 0.163 | 0.014 | 11.972 | 0.000 |
| farmi_6 -> FARMI | -0.173*** | -0.173 | 0.014 | -12.385 | 0.000 |
| farmi_7 -> FARMI | 0.227*** | 0.227 | 0.017 | 13.600 | 0.000 |
| farmi_8 -> FARMI | 0.182*** | 0.182 | 0.012 | 14.657 | 0.000 |
| farmi_9 -> FARMI | 0.148*** | 0.148 | 0.013 | 11.812 | 0.000 |
| foodenv_1 -> FOODENV | 0.928*** | 0.928 | 0.008 | 111.853 | 0.000 |
| foodenv_2 -> FOODENV | -0.104*** | -0.103 | 0.015 | -6.956 | 0.000 |
| foodenv_3 -> FOODENV | -0.045*** | -0.045 | 0.013 | -3.395 | 0.001 |
| foodenv_4 -> FOODENV | 0.162*** | 0.162 | 0.015 | 10.660 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.241*** | 0.239 | 0.023 | 10.403 | 0.000 |
| infra_2 -> INFRA | 0.189*** | 0.189 | 0.020 | 9.307 | 0.000 |
| infra_3 -> INFRA | 0.29*** | 0.290 | 0.021 | 13.647 | 0.000 |
| infra_4 -> INFRA | 0.682*** | 0.682 | 0.018 | 38.835 | 0.000 |
| infra_5 -> INFRA | 0.078*** | 0.078 | 0.020 | 3.947 | 0.000 |
| nutri_1 -> NUTRI | -0.271*** | -0.271 | 0.058 | -4.695 | 0.000 |
| nutri_2 -> NUTRI | -0.102*** | -0.103 | 0.037 | -2.761 | 0.006 |
| nutri_4 -> NUTRI | 1.249*** | 1.248 | 0.042 | 29.427 | 0.000 |
| Scenario B | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.53*** | 0.531 | 0.041 | 12.888 | 0.000 |
| ecosy_2 -> ECOSY | 0.526*** | 0.525 | 0.042 | 12.511 | 0.000 |
| ecosy_3 -> ECOSY | 0.025 | 0.025 | 0.020 | 1.261 | 0.207 |
| envir_1 -> ENVIR | 0.52 | 0.515 | 0.437 | 1.190 | 0.234 |
| envir_2 -> ENVIR | 0.673 | 0.472 | 0.523 | 1.289 | 0.198 |
| farmi_1 -> FARMI | 0.492*** | 0.491 | 0.017 | 28.479 | 0.000 |
| farmi_2 -> FARMI | -0.619*** | -0.620 | 0.032 | -19.175 | 0.000 |
| farmi_3 -> FARMI | -0.459*** | -0.459 | 0.029 | -15.606 | 0.000 |
| farmi_4 -> FARMI | -0.015 | -0.015 | 0.014 | -1.096 | 0.273 |
| farmi_5 -> FARMI | 0.175*** | 0.174 | 0.015 | 11.895 | 0.000 |
| farmi_6 -> FARMI | -0.152*** | -0.153 | 0.015 | -10.074 | 0.000 |
| farmi_7 -> FARMI | 0.207*** | 0.206 | 0.017 | 11.915 | 0.000 |
| farmi_8 -> FARMI | 0.153*** | 0.153 | 0.013 | 11.406 | 0.000 |
| farmi_9 -> FARMI | 0.14*** | 0.140 | 0.014 | 10.153 | 0.000 |
| foodenv_1 -> FOODENV | 0.93*** | 0.930 | 0.009 | 105.794 | 0.000 |
| foodenv_2 -> FOODENV | -0.094*** | -0.093 | 0.016 | -5.904 | 0.000 |
| foodenv_3 -> FOODENV | -0.064*** | -0.064 | 0.014 | -4.711 | 0.000 |
| foodenv_4 -> FOODENV | 0.154*** | 0.154 | 0.016 | 9.488 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.211*** | 0.208 | 0.027 | 7.922 | 0.000 |
| infra_2 -> INFRA | 0.207*** | 0.206 | 0.024 | 8.785 | 0.000 |
| infra_3 -> INFRA | 0.29*** | 0.291 | 0.025 | 11.703 | 0.000 |
| infra_4 -> INFRA | 0.694*** | 0.694 | 0.020 | 35.198 | 0.000 |
| infra_5 -> INFRA | 0.089*** | 0.090 | 0.024 | 3.703 | 0.000 |
| nutri_1 -> NUTRI | -0.257*** | -0.258 | 0.064 | -4.048 | 0.000 |
| nutri_2 -> NUTRI | -0.096** | -0.095 | 0.040 | -2.414 | 0.016 |
| nutri_4 -> NUTRI | 1.237*** | 1.236 | 0.047 | 26.296 | 0.000 |
print_boot_tbl(boot_results_refined_loadings,
paste0("<b><span style='color:black'>Bootstrapped Indicator Loadings (Refined Model)</span></b><br>",
"<span style='font-size:90%;color:gray'>Significance levels are denoted as follows: ***p < 0.01, **p < 0.05, *p < 0.10.</span>"))
| Indicator | Original Est. | Bootstrap Mean | Bootstrap SD | T Stat. | p-value |
|---|---|---|---|---|---|
| Main PLS-SEM | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.952*** | 0.952 | 0.008 | 126.419 | 0.000 |
| ecosy_2 -> ECOSY | 0.951*** | 0.951 | 0.007 | 128.747 | 0.000 |
| ecosy_3 -> ECOSY | -0.02 | -0.021 | 0.024 | -0.833 | 0.405 |
| envir_1 -> ENVIR | 0.923*** | 0.834 | 0.228 | 4.059 | 0.000 |
| envir_2 -> ENVIR | 0.72** | 0.640 | 0.305 | 2.356 | 0.019 |
| farmi_1 -> FARMI | 0.788*** | 0.787 | 0.011 | 73.400 | 0.000 |
| farmi_2 -> FARMI | -0.651*** | -0.651 | 0.011 | -57.938 | 0.000 |
| farmi_3 -> FARMI | 0.354*** | 0.355 | 0.016 | 22.493 | 0.000 |
| farmi_4 -> FARMI | 0.391*** | 0.390 | 0.016 | 24.032 | 0.000 |
| farmi_5 -> FARMI | 0.501*** | 0.500 | 0.015 | 33.495 | 0.000 |
| farmi_6 -> FARMI | -0.352*** | -0.353 | 0.020 | -17.639 | 0.000 |
| farmi_7 -> FARMI | 0.596*** | 0.595 | 0.015 | 40.819 | 0.000 |
| farmi_8 -> FARMI | 0.331*** | 0.331 | 0.018 | 18.571 | 0.000 |
| farmi_9 -> FARMI | 0.384*** | 0.383 | 0.017 | 23.098 | 0.000 |
| foodenv_1 -> FOODENV | 0.983*** | 0.983 | 0.003 | 367.843 | 0.000 |
| foodenv_2 -> FOODENV | -0.053** | -0.053 | 0.020 | -2.584 | 0.010 |
| foodenv_3 -> FOODENV | 0.098*** | 0.096 | 0.020 | 4.868 | 0.000 |
| foodenv_4 -> FOODENV | 0.519*** | 0.518 | 0.016 | 32.600 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.56*** | 0.559 | 0.021 | 27.007 | 0.000 |
| infra_2 -> INFRA | 0.5*** | 0.499 | 0.020 | 25.344 | 0.000 |
| infra_3 -> INFRA | 0.581*** | 0.581 | 0.018 | 31.714 | 0.000 |
| infra_4 -> INFRA | 0.85*** | 0.850 | 0.012 | 70.562 | 0.000 |
| infra_5 -> INFRA | 0.282*** | 0.282 | 0.023 | 12.406 | 0.000 |
| nutri_1 -> NUTRI | 0.683*** | 0.683 | 0.025 | 27.834 | 0.000 |
| nutri_2 -> NUTRI | 0.388*** | 0.387 | 0.031 | 12.456 | 0.000 |
| nutri_4 -> NUTRI | 0.981*** | 0.980 | 0.007 | 146.647 | 0.000 |
| Scenario A | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.95*** | 0.949 | 0.009 | 110.079 | 0.000 |
| ecosy_2 -> ECOSY | 0.954*** | 0.953 | 0.007 | 139.044 | 0.000 |
| ecosy_3 -> ECOSY | -0.016 | -0.017 | 0.024 | -0.658 | 0.510 |
| envir_1 -> ENVIR | 0.91*** | 0.813 | 0.243 | 3.738 | 0.000 |
| envir_2 -> ENVIR | 0.742** | 0.643 | 0.326 | 2.280 | 0.023 |
| farmi_1 -> FARMI | 0.824*** | 0.823 | 0.009 | 90.033 | 0.000 |
| farmi_2 -> FARMI | -0.646*** | -0.646 | 0.011 | -57.954 | 0.000 |
| farmi_3 -> FARMI | 0.353*** | 0.353 | 0.016 | 22.616 | 0.000 |
| farmi_4 -> FARMI | 0.385*** | 0.385 | 0.016 | 23.883 | 0.000 |
| farmi_5 -> FARMI | 0.497*** | 0.496 | 0.015 | 33.487 | 0.000 |
| farmi_6 -> FARMI | -0.352*** | -0.352 | 0.020 | -17.870 | 0.000 |
| farmi_7 -> FARMI | 0.588*** | 0.587 | 0.015 | 40.438 | 0.000 |
| farmi_8 -> FARMI | 0.328*** | 0.329 | 0.018 | 18.683 | 0.000 |
| farmi_9 -> FARMI | 0.379*** | 0.378 | 0.016 | 23.054 | 0.000 |
| foodenv_1 -> FOODENV | 0.983*** | 0.982 | 0.003 | 364.787 | 0.000 |
| foodenv_2 -> FOODENV | -0.052** | -0.051 | 0.020 | -2.539 | 0.011 |
| foodenv_3 -> FOODENV | 0.023 | 0.021 | 0.020 | 1.164 | 0.245 |
| foodenv_4 -> FOODENV | 0.516*** | 0.516 | 0.016 | 32.553 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.559*** | 0.557 | 0.021 | 27.210 | 0.000 |
| infra_2 -> INFRA | 0.503*** | 0.502 | 0.020 | 25.654 | 0.000 |
| infra_3 -> INFRA | 0.582*** | 0.582 | 0.018 | 31.719 | 0.000 |
| infra_4 -> INFRA | 0.849*** | 0.849 | 0.012 | 70.533 | 0.000 |
| infra_5 -> INFRA | 0.28*** | 0.280 | 0.023 | 12.280 | 0.000 |
| nutri_1 -> NUTRI | 0.685*** | 0.685 | 0.025 | 27.847 | 0.000 |
| nutri_2 -> NUTRI | 0.387*** | 0.386 | 0.031 | 12.370 | 0.000 |
| nutri_4 -> NUTRI | 0.981*** | 0.980 | 0.007 | 147.534 | 0.000 |
| Scenario B | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.948*** | 0.947 | 0.010 | 96.248 | 0.000 |
| ecosy_2 -> ECOSY | 0.948*** | 0.947 | 0.008 | 115.274 | 0.000 |
| ecosy_3 -> ECOSY | -0.029 | -0.028 | 0.026 | -1.086 | 0.277 |
| envir_1 -> ENVIR | 0.785*** | 0.701 | 0.301 | 2.609 | 0.009 |
| envir_2 -> ENVIR | 0.878** | 0.674 | 0.400 | 2.194 | 0.028 |
| farmi_1 -> FARMI | 0.833*** | 0.832 | 0.010 | 84.479 | 0.000 |
| farmi_2 -> FARMI | -0.661*** | -0.661 | 0.012 | -55.059 | 0.000 |
| farmi_3 -> FARMI | 0.392*** | 0.392 | 0.017 | 23.150 | 0.000 |
| farmi_4 -> FARMI | 0.319*** | 0.319 | 0.018 | 17.365 | 0.000 |
| farmi_5 -> FARMI | 0.524*** | 0.523 | 0.016 | 33.157 | 0.000 |
| farmi_6 -> FARMI | -0.396*** | -0.397 | 0.021 | -18.836 | 0.000 |
| farmi_7 -> FARMI | 0.564*** | 0.563 | 0.016 | 34.886 | 0.000 |
| farmi_8 -> FARMI | 0.323*** | 0.323 | 0.020 | 16.531 | 0.000 |
| farmi_9 -> FARMI | 0.342*** | 0.342 | 0.019 | 18.164 | 0.000 |
| foodenv_1 -> FOODENV | 0.983*** | 0.983 | 0.003 | 347.643 | 0.000 |
| foodenv_2 -> FOODENV | -0.04* | -0.039 | 0.022 | -1.824 | 0.068 |
| foodenv_3 -> FOODENV | -0.064*** | -0.064 | 0.020 | -3.163 | 0.002 |
| foodenv_4 -> FOODENV | 0.502*** | 0.502 | 0.018 | 28.438 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.527*** | 0.525 | 0.024 | 22.403 | 0.000 |
| infra_2 -> INFRA | 0.524*** | 0.523 | 0.022 | 24.362 | 0.000 |
| infra_3 -> INFRA | 0.56*** | 0.560 | 0.022 | 25.761 | 0.000 |
| infra_4 -> INFRA | 0.857*** | 0.857 | 0.013 | 63.680 | 0.000 |
| infra_5 -> INFRA | 0.261*** | 0.261 | 0.027 | 9.699 | 0.000 |
| nutri_1 -> NUTRI | 0.697*** | 0.696 | 0.027 | 26.192 | 0.000 |
| nutri_2 -> NUTRI | 0.391*** | 0.392 | 0.033 | 11.721 | 0.000 |
| nutri_4 -> NUTRI | 0.984*** | 0.982 | 0.007 | 146.002 | 0.000 |
boot_results_full_weights <- list(
"Main PLS-SEM" = add_pval(s_boot_full$`Main PLS-SEM`$bootstrapped_weights, data_main),
"Scenario A" = add_pval(s_boot_full$`Scenario A`$bootstrapped_weights, data_winsorize),
"Scenario B" = add_pval(s_boot_full$`Scenario B`$bootstrapped_weights, data_deletion)
)
boot_results_full_loadings <- list(
"Main PLS-SEM" = add_pval(s_boot_full$`Main PLS-SEM`$bootstrapped_loadings, data_main),
"Scenario A" = add_pval(s_boot_full$`Scenario A`$bootstrapped_loadings, data_winsorize),
"Scenario B" = add_pval(s_boot_full$`Scenario B`$bootstrapped_loadings, data_deletion)
)
print_boot_tbl(boot_results_full_weights,
paste0("<b><span style='color:black'>Bootstrapped Indicator Weights (Full Model)</span></b><br>",
"<span style='font-size:90%;color:gray'>Significance levels are denoted as follows: ***p < 0.01, **p < 0.05, *p < 0.10.</span>"))
| Indicator | Original Est. | Bootstrap Mean | Bootstrap SD | T Stat. | p-value |
|---|---|---|---|---|---|
| Main PLS-SEM | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.531*** | 0.531 | 0.035 | 15.141 | 0.000 |
| ecosy_2 -> ECOSY | 0.521*** | 0.520 | 0.035 | 14.803 | 0.000 |
| ecosy_3 -> ECOSY | 0.024 | 0.024 | 0.019 | 1.297 | 0.195 |
| envir_1 -> ENVIR | 0.758** | 0.683 | 0.357 | 2.123 | 0.034 |
| envir_2 -> ENVIR | 0.417 | 0.360 | 0.425 | 0.983 | 0.326 |
| farmi_1 -> FARMI | 0.412*** | 0.412 | 0.017 | 24.915 | 0.000 |
| farmi_2 -> FARMI | -0.658*** | -0.658 | 0.030 | -21.762 | 0.000 |
| farmi_3 -> FARMI | -0.502*** | -0.502 | 0.028 | -18.254 | 0.000 |
| farmi_4 -> FARMI | 0.004 | 0.004 | 0.014 | 0.309 | 0.757 |
| farmi_5 -> FARMI | 0.172*** | 0.171 | 0.014 | 12.254 | 0.000 |
| farmi_6 -> FARMI | -0.205*** | -0.205 | 0.014 | -14.323 | 0.000 |
| farmi_7 -> FARMI | 0.236*** | 0.236 | 0.017 | 13.738 | 0.000 |
| farmi_8 -> FARMI | 0.19*** | 0.190 | 0.013 | 14.484 | 0.000 |
| farmi_9 -> FARMI | 0.161*** | 0.161 | 0.013 | 12.502 | 0.000 |
| foodenv_1 -> FOODENV | 0.924*** | 0.924 | 0.008 | 109.051 | 0.000 |
| foodenv_2 -> FOODENV | -0.081*** | -0.080 | 0.015 | -5.353 | 0.000 |
| foodenv_3 -> FOODENV | -0.026** | -0.028 | 0.013 | -2.003 | 0.045 |
| foodenv_4 -> FOODENV | 0.173*** | 0.173 | 0.015 | 11.220 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.238*** | 0.236 | 0.023 | 10.192 | 0.000 |
| infra_2 -> INFRA | 0.185*** | 0.184 | 0.021 | 9.012 | 0.000 |
| infra_3 -> INFRA | 0.293*** | 0.293 | 0.021 | 13.776 | 0.000 |
| infra_4 -> INFRA | 0.685*** | 0.685 | 0.018 | 38.958 | 0.000 |
| infra_5 -> INFRA | 0.078*** | 0.078 | 0.020 | 3.928 | 0.000 |
| nutri_1 -> NUTRI | -0.245*** | -0.244 | 0.044 | -5.545 | 0.000 |
| nutri_2 -> NUTRI | -1.037*** | -1.037 | 0.044 | -23.706 | 0.000 |
| nutri_3 -> NUTRI | -0.162* | -0.160 | 0.085 | -1.899 | 0.058 |
| nutri_4 -> NUTRI | 0.599*** | 0.598 | 0.064 | 9.293 | 0.000 |
| nutri_5 -> NUTRI | 1.5*** | 1.498 | 0.077 | 19.564 | 0.000 |
| Scenario A | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.517*** | 0.518 | 0.036 | 14.212 | 0.000 |
| ecosy_2 -> ECOSY | 0.534*** | 0.533 | 0.037 | 14.425 | 0.000 |
| ecosy_3 -> ECOSY | 0.028 | 0.028 | 0.018 | 1.540 | 0.124 |
| envir_1 -> ENVIR | 0.726* | 0.655 | 0.376 | 1.933 | 0.053 |
| envir_2 -> ENVIR | 0.457 | 0.379 | 0.445 | 1.027 | 0.305 |
| farmi_1 -> FARMI | 0.452*** | 0.451 | 0.016 | 27.896 | 0.000 |
| farmi_2 -> FARMI | -0.632*** | -0.633 | 0.029 | -21.647 | 0.000 |
| farmi_3 -> FARMI | -0.488*** | -0.488 | 0.026 | -18.436 | 0.000 |
| farmi_4 -> FARMI | -0.007 | -0.008 | 0.013 | -0.565 | 0.572 |
| farmi_5 -> FARMI | 0.163*** | 0.163 | 0.014 | 11.934 | 0.000 |
| farmi_6 -> FARMI | -0.184*** | -0.185 | 0.014 | -13.254 | 0.000 |
| farmi_7 -> FARMI | 0.223*** | 0.223 | 0.017 | 13.295 | 0.000 |
| farmi_8 -> FARMI | 0.177*** | 0.178 | 0.013 | 13.924 | 0.000 |
| farmi_9 -> FARMI | 0.156*** | 0.156 | 0.013 | 12.407 | 0.000 |
| foodenv_1 -> FOODENV | 0.924*** | 0.924 | 0.008 | 109.509 | 0.000 |
| foodenv_2 -> FOODENV | -0.08*** | -0.079 | 0.015 | -5.356 | 0.000 |
| foodenv_3 -> FOODENV | -0.058*** | -0.059 | 0.013 | -4.468 | 0.000 |
| foodenv_4 -> FOODENV | 0.172*** | 0.172 | 0.015 | 11.303 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.236*** | 0.235 | 0.023 | 10.212 | 0.000 |
| infra_2 -> INFRA | 0.189*** | 0.188 | 0.020 | 9.219 | 0.000 |
| infra_3 -> INFRA | 0.294*** | 0.294 | 0.021 | 13.800 | 0.000 |
| infra_4 -> INFRA | 0.684*** | 0.684 | 0.018 | 38.942 | 0.000 |
| infra_5 -> INFRA | 0.076*** | 0.076 | 0.020 | 3.802 | 0.000 |
| nutri_1 -> NUTRI | -0.24*** | -0.240 | 0.044 | -5.437 | 0.000 |
| nutri_2 -> NUTRI | -1.043*** | -1.043 | 0.044 | -23.934 | 0.000 |
| nutri_3 -> NUTRI | -0.167* | -0.165 | 0.085 | -1.960 | 0.050 |
| nutri_4 -> NUTRI | 0.595*** | 0.593 | 0.064 | 9.231 | 0.000 |
| nutri_5 -> NUTRI | 1.51*** | 1.507 | 0.076 | 19.746 | 0.000 |
| Scenario B | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.53*** | 0.531 | 0.041 | 12.877 | 0.000 |
| ecosy_2 -> ECOSY | 0.526*** | 0.524 | 0.042 | 12.487 | 0.000 |
| ecosy_3 -> ECOSY | 0.025 | 0.025 | 0.020 | 1.253 | 0.210 |
| envir_1 -> ENVIR | 0.518 | 0.515 | 0.442 | 1.172 | 0.241 |
| envir_2 -> ENVIR | 0.675 | 0.464 | 0.533 | 1.268 | 0.205 |
| farmi_1 -> FARMI | 0.479*** | 0.478 | 0.017 | 27.489 | 0.000 |
| farmi_2 -> FARMI | -0.642*** | -0.643 | 0.033 | -19.742 | 0.000 |
| farmi_3 -> FARMI | -0.475*** | -0.475 | 0.030 | -16.065 | 0.000 |
| farmi_4 -> FARMI | -0.02 | -0.021 | 0.014 | -1.491 | 0.136 |
| farmi_5 -> FARMI | 0.173*** | 0.173 | 0.015 | 11.816 | 0.000 |
| farmi_6 -> FARMI | -0.163*** | -0.164 | 0.015 | -10.763 | 0.000 |
| farmi_7 -> FARMI | 0.206*** | 0.205 | 0.017 | 11.859 | 0.000 |
| farmi_8 -> FARMI | 0.148*** | 0.148 | 0.014 | 10.712 | 0.000 |
| farmi_9 -> FARMI | 0.147*** | 0.146 | 0.014 | 10.687 | 0.000 |
| foodenv_1 -> FOODENV | 0.926*** | 0.926 | 0.009 | 103.525 | 0.000 |
| foodenv_2 -> FOODENV | -0.071*** | -0.070 | 0.016 | -4.478 | 0.000 |
| foodenv_3 -> FOODENV | -0.072*** | -0.072 | 0.014 | -5.291 | 0.000 |
| foodenv_4 -> FOODENV | 0.162*** | 0.162 | 0.016 | 9.911 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.207*** | 0.205 | 0.027 | 7.778 | 0.000 |
| infra_2 -> INFRA | 0.206*** | 0.204 | 0.024 | 8.690 | 0.000 |
| infra_3 -> INFRA | 0.294*** | 0.295 | 0.025 | 11.857 | 0.000 |
| infra_4 -> INFRA | 0.695*** | 0.695 | 0.020 | 35.231 | 0.000 |
| infra_5 -> INFRA | 0.087*** | 0.088 | 0.024 | 3.603 | 0.000 |
| nutri_1 -> NUTRI | -0.214*** | -0.215 | 0.047 | -4.537 | 0.000 |
| nutri_2 -> NUTRI | -1.027*** | -1.026 | 0.045 | -22.654 | 0.000 |
| nutri_3 -> NUTRI | -0.228** | -0.228 | 0.090 | -2.535 | 0.011 |
| nutri_4 -> NUTRI | 0.584*** | 0.583 | 0.069 | 8.431 | 0.000 |
| nutri_5 -> NUTRI | 1.543*** | 1.542 | 0.080 | 19.278 | 0.000 |
print_boot_tbl(boot_results_full_loadings,
paste0("<b><span style='color:black'>Bootstrapped Indicator Loadings (Full Model)</span></b><br>",
"<span style='font-size:90%;color:gray'>Significance levels are denoted as follows: ***p < 0.01, **p < 0.05, *p < 0.10.</span>"))
| Indicator | Original Est. | Bootstrap Mean | Bootstrap SD | T Stat. | p-value |
|---|---|---|---|---|---|
| Main PLS-SEM | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.952*** | 0.952 | 0.008 | 126.253 | 0.000 |
| ecosy_2 -> ECOSY | 0.951*** | 0.951 | 0.007 | 128.326 | 0.000 |
| ecosy_3 -> ECOSY | -0.02 | -0.021 | 0.024 | -0.832 | 0.406 |
| envir_1 -> ENVIR | 0.924*** | 0.826 | 0.238 | 3.883 | 0.000 |
| envir_2 -> ENVIR | 0.719** | 0.632 | 0.318 | 2.259 | 0.024 |
| farmi_1 -> FARMI | 0.78*** | 0.779 | 0.011 | 71.782 | 0.000 |
| farmi_2 -> FARMI | -0.657*** | -0.657 | 0.011 | -58.671 | 0.000 |
| farmi_3 -> FARMI | 0.358*** | 0.358 | 0.016 | 22.767 | 0.000 |
| farmi_4 -> FARMI | 0.382*** | 0.382 | 0.016 | 23.397 | 0.000 |
| farmi_5 -> FARMI | 0.503*** | 0.503 | 0.015 | 33.779 | 0.000 |
| farmi_6 -> FARMI | -0.362*** | -0.362 | 0.020 | -18.318 | 0.000 |
| farmi_7 -> FARMI | 0.592*** | 0.592 | 0.015 | 40.776 | 0.000 |
| farmi_8 -> FARMI | 0.327*** | 0.327 | 0.018 | 18.049 | 0.000 |
| farmi_9 -> FARMI | 0.388*** | 0.387 | 0.017 | 23.524 | 0.000 |
| foodenv_1 -> FOODENV | 0.984*** | 0.984 | 0.003 | 376.503 | 0.000 |
| foodenv_2 -> FOODENV | -0.029 | -0.029 | 0.021 | -1.404 | 0.160 |
| foodenv_3 -> FOODENV | 0.087*** | 0.085 | 0.020 | 4.375 | 0.000 |
| foodenv_4 -> FOODENV | 0.526*** | 0.526 | 0.016 | 33.308 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.557*** | 0.555 | 0.021 | 26.816 | 0.000 |
| infra_2 -> INFRA | 0.5*** | 0.499 | 0.020 | 25.205 | 0.000 |
| infra_3 -> INFRA | 0.583*** | 0.583 | 0.018 | 31.794 | 0.000 |
| infra_4 -> INFRA | 0.851*** | 0.851 | 0.012 | 70.831 | 0.000 |
| infra_5 -> INFRA | 0.279*** | 0.279 | 0.023 | 12.234 | 0.000 |
| nutri_1 -> NUTRI | 0.557*** | 0.556 | 0.022 | 25.513 | 0.000 |
| nutri_2 -> NUTRI | 0.309*** | 0.308 | 0.026 | 12.112 | 0.000 |
| nutri_3 -> NUTRI | 0.794*** | 0.793 | 0.016 | 50.399 | 0.000 |
| nutri_4 -> NUTRI | 0.793*** | 0.791 | 0.016 | 49.509 | 0.000 |
| nutri_5 -> NUTRI | 0.741*** | 0.739 | 0.017 | 43.206 | 0.000 |
| Scenario A | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.95*** | 0.949 | 0.009 | 110.296 | 0.000 |
| ecosy_2 -> ECOSY | 0.954*** | 0.953 | 0.007 | 138.121 | 0.000 |
| ecosy_3 -> ECOSY | -0.016 | -0.017 | 0.024 | -0.661 | 0.509 |
| envir_1 -> ENVIR | 0.908*** | 0.806 | 0.252 | 3.600 | 0.000 |
| envir_2 -> ENVIR | 0.746** | 0.640 | 0.334 | 2.234 | 0.025 |
| farmi_1 -> FARMI | 0.816*** | 0.816 | 0.009 | 87.485 | 0.000 |
| farmi_2 -> FARMI | -0.652*** | -0.652 | 0.011 | -58.663 | 0.000 |
| farmi_3 -> FARMI | 0.356*** | 0.357 | 0.016 | 22.880 | 0.000 |
| farmi_4 -> FARMI | 0.377*** | 0.376 | 0.016 | 23.273 | 0.000 |
| farmi_5 -> FARMI | 0.499*** | 0.499 | 0.015 | 33.758 | 0.000 |
| farmi_6 -> FARMI | -0.361*** | -0.361 | 0.019 | -18.528 | 0.000 |
| farmi_7 -> FARMI | 0.585*** | 0.584 | 0.014 | 40.425 | 0.000 |
| farmi_8 -> FARMI | 0.324*** | 0.325 | 0.018 | 18.149 | 0.000 |
| farmi_9 -> FARMI | 0.383*** | 0.382 | 0.016 | 23.493 | 0.000 |
| foodenv_1 -> FOODENV | 0.983*** | 0.983 | 0.003 | 368.997 | 0.000 |
| foodenv_2 -> FOODENV | -0.028 | -0.027 | 0.020 | -1.357 | 0.175 |
| foodenv_3 -> FOODENV | 0.01 | 0.008 | 0.019 | 0.494 | 0.621 |
| foodenv_4 -> FOODENV | 0.524*** | 0.524 | 0.016 | 33.263 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.556*** | 0.554 | 0.021 | 27.004 | 0.000 |
| infra_2 -> INFRA | 0.503*** | 0.501 | 0.020 | 25.512 | 0.000 |
| infra_3 -> INFRA | 0.584*** | 0.584 | 0.018 | 31.808 | 0.000 |
| infra_4 -> INFRA | 0.85*** | 0.850 | 0.012 | 70.801 | 0.000 |
| infra_5 -> INFRA | 0.277*** | 0.277 | 0.023 | 12.108 | 0.000 |
| nutri_1 -> NUTRI | 0.557*** | 0.556 | 0.022 | 25.547 | 0.000 |
| nutri_2 -> NUTRI | 0.308*** | 0.307 | 0.026 | 12.056 | 0.000 |
| nutri_3 -> NUTRI | 0.793*** | 0.792 | 0.016 | 50.223 | 0.000 |
| nutri_4 -> NUTRI | 0.791*** | 0.790 | 0.016 | 49.399 | 0.000 |
| nutri_5 -> NUTRI | 0.74*** | 0.739 | 0.017 | 43.178 | 0.000 |
| Scenario B | |||||
| clima -> CLIMA | 1 | 1.000 | 0.000 | NA | NA |
| ecosy_1 -> ECOSY | 0.948*** | 0.947 | 0.010 | 96.401 | 0.000 |
| ecosy_2 -> ECOSY | 0.948*** | 0.947 | 0.008 | 114.751 | 0.000 |
| ecosy_3 -> ECOSY | -0.029 | -0.028 | 0.026 | -1.082 | 0.279 |
| envir_1 -> ENVIR | 0.784** | 0.697 | 0.304 | 2.581 | 0.010 |
| envir_2 -> ENVIR | 0.879** | 0.666 | 0.409 | 2.149 | 0.032 |
| farmi_1 -> FARMI | 0.826*** | 0.825 | 0.010 | 81.998 | 0.000 |
| farmi_2 -> FARMI | -0.666*** | -0.666 | 0.012 | -55.534 | 0.000 |
| farmi_3 -> FARMI | 0.394*** | 0.394 | 0.017 | 23.324 | 0.000 |
| farmi_4 -> FARMI | 0.312*** | 0.312 | 0.018 | 16.903 | 0.000 |
| farmi_5 -> FARMI | 0.524*** | 0.524 | 0.016 | 33.426 | 0.000 |
| farmi_6 -> FARMI | -0.403*** | -0.403 | 0.021 | -19.239 | 0.000 |
| farmi_7 -> FARMI | 0.564*** | 0.563 | 0.016 | 35.064 | 0.000 |
| farmi_8 -> FARMI | 0.317*** | 0.318 | 0.020 | 15.912 | 0.000 |
| farmi_9 -> FARMI | 0.347*** | 0.347 | 0.019 | 18.613 | 0.000 |
| foodenv_1 -> FOODENV | 0.984*** | 0.983 | 0.003 | 352.374 | 0.000 |
| foodenv_2 -> FOODENV | -0.017 | -0.016 | 0.022 | -0.777 | 0.437 |
| foodenv_3 -> FOODENV | -0.072*** | -0.072 | 0.020 | -3.562 | 0.000 |
| foodenv_4 -> FOODENV | 0.509*** | 0.509 | 0.018 | 28.967 | 0.000 |
| foodsec -> FOODSEC | 1 | 1.000 | 0.000 | NA | NA |
| infra_1 -> INFRA | 0.525*** | 0.522 | 0.024 | 22.265 | 0.000 |
| infra_2 -> INFRA | 0.523*** | 0.522 | 0.022 | 24.214 | 0.000 |
| infra_3 -> INFRA | 0.563*** | 0.562 | 0.022 | 25.897 | 0.000 |
| infra_4 -> INFRA | 0.857*** | 0.857 | 0.013 | 63.722 | 0.000 |
| infra_5 -> INFRA | 0.259*** | 0.259 | 0.027 | 9.579 | 0.000 |
| nutri_1 -> NUTRI | 0.564*** | 0.563 | 0.023 | 24.153 | 0.000 |
| nutri_2 -> NUTRI | 0.311*** | 0.311 | 0.027 | 11.520 | 0.000 |
| nutri_3 -> NUTRI | 0.792*** | 0.791 | 0.017 | 47.915 | 0.000 |
| nutri_4 -> NUTRI | 0.789*** | 0.788 | 0.017 | 46.016 | 0.000 |
| nutri_5 -> NUTRI | 0.751*** | 0.750 | 0.018 | 42.283 | 0.000 |
Consistency of Indicator Signs (Formative Weights). The signs of formative weights are not validity criteria, but provide a useful theory check. The assessment by construct shows the following patterns:
CLIMA and FOODSEC.
Single-item constructs with inherently negative indicators, already
recoded so that higher values indicate more favorable conditions.ECOSY, ENVIR, and
INFRA. All indicators behaved consistently with
theory, confirming positive/favorable constructs for Ecosystems
Conservation Practices, Environmental Governance, and
Infrastructure and Support.FARMI. Mixed results. Protective and
sustainable practices, farmi_1 (ig52),
farmi_8 (v4), and farmi_9 (c2), aligned with
theory, and inorganic fertilization, farmi_3 (n2), was
negative as expected. Yet, some “positive” items,
farmi_2 (n1) and farmi_6 (r2), turned
negative, while inverse-expected ones, farmi_5 (pa3) and
farmi_7 (v3), loaded positively. These reversals reflect
contextual trade-offs in municipalities agriculture (e.g., crop
specialization, input intensity), suggesting FARMI should
be interpreted as a composite balance rather than independent monotonic
effects.FOODENV. Results showed systematic
sign reversals: unhealthy outlets, foodenv_1 (b3), was
expected to load inversely but was consistently positive, while the
presence of healthy outlets, foodenv_2 (b4), and open-air
markets, foodenv_3 (b5), loaded negatively, opposite to
theory. Only access to water supply, foodenv_4 (ii3),
behaved consistently (positive). These patterns suggest that, in
practice, municipalities with more commercial food infrastructure may
simultaneously host both healthy and unhealthy options, creating
empirical trade-offs that invert expected signs. Rather than
invalidating the construct, this reflects the complexity of local food
environments, where structural composition matters more than monotonic
effects of individual indicatorsNUTRI. Mixed signs. Indicators for
children 5-10 and adults, nutri_4 (h1) and
nutri_5 (h2), were consistent, whereas infants,
adolescents, and elderly measures, nutri_1-3 (f1-f2-f3),
were negative. These reversals likely capture contextual dynamics in
nutrition monitoring and do not compromise construct validity.indicator_summary <- tribble(
~Construct, ~Indicator, ~"Theoretical relation", ~"Empirical consistency",
"ECOSY", "ecosy_1 (ig51)", "Direct", "ok",
"ECOSY", "ecosy_2 (ig53)", "Direct", "ok",
"ECOSY", "ecosy_3 (ii1)", "Direct", "ok",
"ENVIR", "envir_1 (w1)", "Direct", "ok",
"ENVIR", "envir_2 (w2)", "Direct", "ok",
"FARMI", "farmi_1 (ig52)", "Direct", "ok",
"FARMI", "farmi_2 (n1)", "Direct", "contrary",
"FARMI", "farmi_3 (n2)", "Inverse", "ok",
"FARMI", "farmi_4 (pa1)", "Direct", "mix, insignificant",
"FARMI", "farmi_5 (pa3)", "Inverse", "contrary",
"FARMI", "farmi_6 (r2)", "Direct", "contrary",
"FARMI", "farmi_7 (v3)", "Inverse", "contrary",
"FARMI", "farmi_8 (v4)", "Direct", "ok",
"FARMI", "farmi_9 (c2)", "Direct", "ok",
"FOODENV", "foodenv_1 (b3)", "Inverse", "contrary",
"FOODENV", "foodenv_2 (b4)", "Direct", "contrary",
"FOODENV", "foodenv_3 (b5)", "Direct", "contrary",
"FOODENV", "foodenv_4 (ii3)", "Direct", "ok",
"INFRA", "infra_1 (ig8)", "Direct", "ok",
"INFRA", "infra_2 (ii5)", "Direct", "ok",
"INFRA", "infra_3 (ii6)", "Direct", "ok",
"INFRA", "infra_4 (ii10)", "Direct", "ok",
"INFRA", "infra_5 (d1)", "Direct", "ok",
"NUTRI", "nutri_1 (f1)", "Direct", "contrary",
"NUTRI", "nutri_2 (f2)", "Direct", "contrary",
"NUTRI", "nutri_3 (f3)", "Direct", "contrary",
"NUTRI", "nutri_4 (h1)", "Direct", "ok",
"NUTRI", "nutri_5 (h2)", "Direct", "ok"
)
scen_cols <- setdiff(names(indicator_summary), c("Construct","Indicator"))
kable_group_by_construct(
indicator_summary,
"<b><span style='color:black'>Consistency between theoretical and empirical directions of formative indicator weights</span></b>",
scen_cols
)
| Indicator | Theoretical relation | Empirical consistency |
|---|---|---|
| ECOSY | ||
| ecosy_1 (ig51) | Direct | ok |
| ecosy_2 (ig53) | Direct | ok |
| ecosy_3 (ii1) | Direct | ok |
| ENVIR | ||
| envir_1 (w1) | Direct | ok |
| envir_2 (w2) | Direct | ok |
| FARMI | ||
| farmi_1 (ig52) | Direct | ok |
| farmi_2 (n1) | Direct | contrary |
| farmi_3 (n2) | Inverse | ok |
| farmi_4 (pa1) | Direct | mix, insignificant |
| farmi_5 (pa3) | Inverse | contrary |
| farmi_6 (r2) | Direct | contrary |
| farmi_7 (v3) | Inverse | contrary |
| farmi_8 (v4) | Direct | ok |
| farmi_9 (c2) | Direct | ok |
| FOODENV | ||
| foodenv_1 (b3) | Inverse | contrary |
| foodenv_2 (b4) | Direct | contrary |
| foodenv_3 (b5) | Direct | contrary |
| foodenv_4 (ii3) | Direct | ok |
| INFRA | ||
| infra_1 (ig8) | Direct | ok |
| infra_2 (ii5) | Direct | ok |
| infra_3 (ii6) | Direct | ok |
| infra_4 (ii10) | Direct | ok |
| infra_5 (d1) | Direct | ok |
| NUTRI | ||
| nutri_1 (f1) | Direct | contrary |
| nutri_2 (f2) | Direct | contrary |
| nutri_3 (f3) | Direct | contrary |
| nutri_4 (h1) | Direct | ok |
| nutri_5 (h2) | Direct | ok |
Key Points (Measurement Evaluation). The measurement model evaluation identified critical collinearity only for
nutri_3 (f3)andnutri_5 (h2), which were excluded in the refined specification. All remaining indicators showed acceptable VIF values, and bootstrapped weights and loadings confirmed their statistical robustness across scenarios. Althoughecosy_3 (ii1)displayed negligible empirical contribution (non-significant weight and loading), it was retained in both models to preserve content validity, as it represents a distinct dimension of ecosystem conservation.
Structural relations were assessed under standard PLS-SEM guidelines, covering collinearity among antecedent constructs, significance and substanteive relevance of path coefficients, explanatory power (\(R^2\), \(f^2\)), and predictive validity (PLSpredict). Results are reported for the Refined Model, which excludes indicators with critical multicollinearity, and the Full Model, which retains all theoretically motivated indicators. For both specifications, estimates are shown for the main dataset and two robustness scenarios (Scenario A: winsorization; Scenario B: listwise deletion).
make_struct_vif <- function(s_list, caption_suffix){
vif_all <- imap_dfr(s_list,
function(vif_list, sc_name){
imap_dfr(vif_list, function(vec, cn){
tibble(
Scenario = sc_name,
Construct = cn,
Predictor = names(vec),
VIF = as.numeric(vec))})
}) %>%
filter(!is.na(VIF), is.finite(VIF)) %>%
mutate(Scenario = factor(Scenario,levels = c("Main PLS-SEM","Scenario A","Scenario B"))) %>%
arrange(Construct, Predictor, Scenario) %>%
select(Construct, Predictor, Scenario, VIF) %>%
pivot_wider(names_from = Scenario, values_from = VIF) %>%
arrange(Construct, Predictor)
scen_cols <- setdiff(names(vif_all), c("Construct","Predictor"))
fmt <- vif_all
fmt[scen_cols] <- lapply(fmt[scen_cols], format_vif_cells)
idx <- fmt %>%
mutate(row_id = row_number()) %>%
group_by(Construct) %>%
summarise(start = min(row_id), end = max(row_id), .groups = "drop")
kb <- kable(fmt %>% select(-Construct),
format = "html",
escape = FALSE,
align = c("l", rep("c", length(scen_cols))),
caption = paste0(
"<b><span style='color:black'>VIF - Structural Model Predictors (",
caption_suffix, ")</span></b>"),
col.names = c("Predictor", scen_cols)) %>%
kable_styling(
bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE,
position = "center",
fixed_thead = TRUE) %>%
add_header_above(c(" " = 1, "Scenarios" = length(scen_cols)))
if (nrow(idx) > 0){
for (i in seq_len(nrow(idx))){
kb <- kb %>% group_rows(idx$Construct[i], idx$start[i], idx$end[i])
}
}
kb
}
print_paths_tbl <- function(df_list, caption){
boot_results_all <- map_dfr(names(df_list), ~{
add_pval(df_list[[.x]]$df, df_list[[.x]]$data) %>%
rownames_to_column("Path") %>%
mutate(Panel = .x)
})
idx <- boot_results_all %>% mutate(row_id = row_number()) %>%
group_by(Panel) %>% summarise(start = min(row_id), end = max(row_id), .groups = "drop")
boot_results_all <- boot_results_all %>%
mutate(signif = case_when(`p-value` < 0.01 ~ "<sup>***</sup>",
`p-value` < 0.05 ~ "<sup>**</sup>",
`p-value` < 0.10 ~ "<sup>*</sup>",
TRUE ~ ""),
`Original Est.` = paste0(round(`Original Est.`, 3), signif))
kb <- kable(boot_results_all %>% select(-c(Panel, signif)),
caption = caption, digits = 3, format = "html",
escape = FALSE, booktabs = TRUE,
align = c("l", rep("c", 5))) %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE, position = "center", fixed_thead = TRUE)
if (nrow(idx) > 0) {
for (i in seq_len(nrow(idx))) {
kb <- kb %>% group_rows(idx$Panel[i], idx$start[i], idx$end[i], bold = TRUE)
}
}
kb
}
Collinearity (antecedent). Variance inflation factors (VIF) were computed for all predictors of each andogenous construct. All values remaind below 3, indicating absence of critical collinearity.
make_struct_vif(
list(
"Main PLS-SEM" = s_main_iter2$vif_antecedents,
"Scenario A" = s_A_iter2$vif_antecedents,
"Scenario B" = s_B_iter2$vif_antecedents
),
"Refined Model"
)
| Predictor | Main PLS-SEM | Scenario A | Scenario B |
|---|---|---|---|
| CLIMA | |||
| ECOSY | 1.904 | 1.942 | 1.978 |
| FARMI | 2.322 | 2.400 | 2.449 |
| FOODENV | 1.534 | 1.554 | 1.596 |
| ECOSY | |||
| ENVIR | 1.003 | 1.003 | 1.005 |
| INFRA | 1.003 | 1.003 | 1.005 |
| FARMI | |||
| ECOSY | 1.181 | 1.182 | 1.152 |
| ENVIR | 1.004 | 1.004 | 1.007 |
| INFRA | 1.185 | 1.185 | 1.158 |
| FOODENV | |||
| ENVIR | 1.003 | 1.003 | 1.006 |
| FARMI | 1.540 | 1.540 | 1.439 |
| INFRA | 1.544 | 1.544 | 1.446 |
| FOODSEC | |||
| FARMI | 1.525 | 1.548 | 1.587 |
| FOODENV | 1.525 | 1.548 | 1.587 |
| NUTRI | |||
| FARMI | 1.525 | 1.548 | 1.587 |
| FOODENV | 1.525 | 1.548 | 1.587 |
make_struct_vif(
list(
"Main PLS-SEM" = s_main$vif_antecedents,
"Scenario A" = s_A$vif_antecedents,
"Scenario B" = s_B$vif_antecedents
),
"Full Model"
)
| Predictor | Main PLS-SEM | Scenario A | Scenario B |
|---|---|---|---|
| CLIMA | |||
| ECOSY | 1.886 | 1.924 | 1.960 |
| FARMI | 2.307 | 2.385 | 2.432 |
| FOODENV | 1.540 | 1.560 | 1.601 |
| ECOSY | |||
| ENVIR | 1.003 | 1.003 | 1.005 |
| INFRA | 1.003 | 1.003 | 1.005 |
| FARMI | |||
| ECOSY | 1.182 | 1.182 | 1.153 |
| ENVIR | 1.004 | 1.004 | 1.007 |
| INFRA | 1.185 | 1.186 | 1.159 |
| FOODENV | |||
| ENVIR | 1.003 | 1.003 | 1.006 |
| FARMI | 1.537 | 1.537 | 1.440 |
| INFRA | 1.541 | 1.541 | 1.446 |
| FOODSEC | |||
| FARMI | 1.531 | 1.554 | 1.591 |
| FOODENV | 1.531 | 1.554 | 1.591 |
| NUTRI | |||
| FARMI | 1.531 | 1.554 | 1.591 |
| FOODENV | 1.531 | 1.554 | 1.591 |
Path coefficients. Bootstrapping (6,000 resamples) shows that several hypothesized relations are robust and substantively meaningful (\(|\beta| \geq 0.20\)), while smaller but significant effects are interpreted with caution.
ENVIR had only
modest effects: small positives on ECOSY and
FOODENV, a non-significant link to FARMI, and
a small but unexpected negative effect on INFRA. These
mixed signs mirror the indicator-level analysis, where
ENVIR behaved consistently positive, but FARMI
indicators showed contextual trade-offs. INFRA, in
contrast, consistently and strongly shaped contextual
ECOSY, FARMI, and FOODENV.ECOSY exerted
one of the strongest effects, consistently driving FARMI
outcomes. FARMI then strongly predicted
FOODENV and FOODSEC. Yet, the formative
weights for FARMI had shown mixed signs, with both
sustainable and input-intensive practices loading together. This
suggests that the strong path coefficients capture FARMI as
a composite balance of protective and intensive practices rather than a
uniform “positive” construct.FOODENV contributed
positively to FOODSEC, consistent across scenarios. But
their effects on CLIMA and NUTRI were weak,
unstable, or contrary to theory. These deviations align with the
formative weight results, where healthy outlets and markets loaded
negatively while unhealthy outlets loaded positively. Together, there
findings suggest that local FOODENV reflect structural
trade-offs between healthy and unhealthy options, rather than monotonic
improvements.FARMI displayed small adverse effects on CLIMA
and NUTRI, and FOODENV negatively predicted
NUTRI. These unexpected signs echo the indicator-level
inconsistencies in NUTRI, where some age-specific measures
loaded in opposite directions. Rather than undermining validity, this
highlights contextual complexities in how FARMI intensity
and FOODENV translate into NUTRI and
CLIMA outcomes.In sum, the model is well supported for the main conduits
(INFRA; ECOSY -> FARMI -> FOODENV -> FOODSEC)
while systematic deviations in NUTRI and CLIMA
parallel the formative indicator reversals, pointing to empirical
trade-offs that deserve further exploration.
The table below summarize these analyses, with full results reported subsequently.
path_summary <- tribble(
~Path, ~Summary,
"ENVIR -> INFRA", "Small but significant negative effect (contrary to theory).",
"ENVIR -> ECOSY", "Small positive, consistent with theory.",
"ENVIR -> FARMI", "Non-significant, contrary to theory.",
"ENVIR -> FOODENV", "Small positive, consistent with theory.",
"INFRA -> ECOSY", "Strong positive, robust across scenarios.",
"INFRA -> FARMI", "Strong positive, robust across scenarios.",
"INFRA -> FOODENV", "Moderate positive, robust across scenarios.",
"ECOSY -> FARMI", "Strongest effect, robust.",
"ECOSY -> CLIMA", "Inconsistent, mix of null/small negative.",
"FARMI -> FOODENV", "Strong positive, robust across scenarios.",
"FARMI -> CLIMA", "Small negative, contrary to theory.",
"FARMI -> NUTRI", "Small-to-moderate negative, contrary to theory.",
"FARMI -> FOODSEC", "Positive and robust across scenarios.",
"FOODENV -> CLIMA", "Mixed, weak and unstable across scenarios.",
"FOODENV -> NUTRI", "Consistently negative, contrary to theory.",
"FOODENV -> FOODSEC", "Strong positive, robust across scenarios."
)
kable(path_summary,
format = "html",
caption = "<b><span style='color:black'>Summary of Path Coefficient Results (Refined and Full Models)</span></b>",
escape = FALSE, booktabs = TRUE,
col.names = c("Path (theory: positive)", "Summary of empirical results")) %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE, position = "center", fixed_thead = TRUE)
| Path (theory: positive) | Summary of empirical results |
|---|---|
| ENVIR -> INFRA | Small but significant negative effect (contrary to theory). |
| ENVIR -> ECOSY | Small positive, consistent with theory. |
| ENVIR -> FARMI | Non-significant, contrary to theory. |
| ENVIR -> FOODENV | Small positive, consistent with theory. |
| INFRA -> ECOSY | Strong positive, robust across scenarios. |
| INFRA -> FARMI | Strong positive, robust across scenarios. |
| INFRA -> FOODENV | Moderate positive, robust across scenarios. |
| ECOSY -> FARMI | Strongest effect, robust. |
| ECOSY -> CLIMA | Inconsistent, mix of null/small negative. |
| FARMI -> FOODENV | Strong positive, robust across scenarios. |
| FARMI -> CLIMA | Small negative, contrary to theory. |
| FARMI -> NUTRI | Small-to-moderate negative, contrary to theory. |
| FARMI -> FOODSEC | Positive and robust across scenarios. |
| FOODENV -> CLIMA | Mixed, weak and unstable across scenarios. |
| FOODENV -> NUTRI | Consistently negative, contrary to theory. |
| FOODENV -> FOODSEC | Strong positive, robust across scenarios. |
print_paths_tbl(
list(
"Main PLS-SEM" = list(
df = s_boot_refined[["Main PLS-SEM"]]$bootstrapped_paths,
data = data_main
),
"Scenario A (Winsorization)" = list(
df = s_boot_refined[["Scenario A"]]$bootstrapped_paths,
data = data_winsorize
),
"Scenario B (Deletion)" = list(
df = s_boot_refined[["Scenario B"]]$bootstrapped_paths,
data = data_deletion
)
),
caption = "<b><span style='color:black'>Bootstrapped Path Coefficients - Refined Model</span></b>"
)
| Path | Original Est. | Bootstrap Mean | Bootstrap SD | T Stat. | p-value |
|---|---|---|---|---|---|
| Main PLS-SEM | |||||
| ENVIR -> INFRA | -0.057*** | -0.054 | 0.022 | -2.640 | 0.008 |
| ENVIR -> ECOSY | 0.029** | 0.026 | 0.014 | 2.045 | 0.041 |
| ENVIR -> FARMI | -0.013 | -0.012 | 0.011 | -1.180 | 0.238 |
| ENVIR -> FOODENV | 0.065*** | 0.060 | 0.021 | 3.143 | 0.002 |
| INFRA -> ECOSY | 0.392*** | 0.393 | 0.012 | 33.354 | 0.000 |
| INFRA -> FARMI | 0.381*** | 0.381 | 0.015 | 25.665 | 0.000 |
| INFRA -> FOODENV | 0.247*** | 0.246 | 0.015 | 16.536 | 0.000 |
| ECOSY -> FARMI | 0.538*** | 0.538 | 0.014 | 37.126 | 0.000 |
| ECOSY -> CLIMA | 0 | 0.000 | 0.030 | -0.011 | 0.991 |
| FARMI -> FOODENV | 0.443*** | 0.444 | 0.014 | 32.101 | 0.000 |
| FARMI -> CLIMA | -0.085*** | -0.087 | 0.023 | -3.783 | 0.000 |
| FARMI -> NUTRI | -0.097*** | -0.097 | 0.017 | -5.854 | 0.000 |
| FARMI -> FOODSEC | 0.406*** | 0.406 | 0.011 | 37.501 | 0.000 |
| FOODENV -> CLIMA | -0.033* | -0.033 | 0.017 | -1.941 | 0.052 |
| FOODENV -> NUTRI | -0.351*** | -0.351 | 0.015 | -22.853 | 0.000 |
| FOODENV -> FOODSEC | 0.482*** | 0.482 | 0.011 | 44.701 | 0.000 |
| Scenario A (Winsorization) | |||||
| ENVIR -> INFRA | -0.058** | -0.054 | 0.022 | -2.590 | 0.010 |
| ENVIR -> ECOSY | 0.029** | 0.026 | 0.015 | 2.015 | 0.044 |
| ENVIR -> FARMI | -0.01 | -0.009 | 0.012 | -0.898 | 0.369 |
| ENVIR -> FOODENV | 0.06*** | 0.054 | 0.020 | 2.908 | 0.004 |
| INFRA -> ECOSY | 0.393*** | 0.393 | 0.012 | 33.417 | 0.000 |
| INFRA -> FARMI | 0.377*** | 0.377 | 0.015 | 25.716 | 0.000 |
| INFRA -> FOODENV | 0.24*** | 0.239 | 0.015 | 16.137 | 0.000 |
| ECOSY -> FARMI | 0.548*** | 0.547 | 0.014 | 38.835 | 0.000 |
| ECOSY -> CLIMA | 0.013 | 0.013 | 0.032 | 0.397 | 0.691 |
| FARMI -> FOODENV | 0.455*** | 0.456 | 0.014 | 33.335 | 0.000 |
| FARMI -> CLIMA | -0.113*** | -0.114 | 0.025 | -4.513 | 0.000 |
| FARMI -> NUTRI | -0.102*** | -0.103 | 0.017 | -6.189 | 0.000 |
| FARMI -> FOODSEC | 0.408*** | 0.408 | 0.011 | 37.733 | 0.000 |
| FOODENV -> CLIMA | -0.019 | -0.018 | 0.016 | -1.195 | 0.232 |
| FOODENV -> NUTRI | -0.345*** | -0.344 | 0.015 | -22.234 | 0.000 |
| FOODENV -> FOODSEC | 0.479*** | 0.479 | 0.011 | 44.145 | 0.000 |
| Scenario B (Deletion) | |||||
| ENVIR -> INFRA | -0.073** | -0.065 | 0.028 | -2.579 | 0.010 |
| ENVIR -> ECOSY | 0.04* | 0.036 | 0.022 | 1.854 | 0.064 |
| ENVIR -> FARMI | -0.013 | -0.011 | 0.012 | -1.065 | 0.287 |
| ENVIR -> FOODENV | 0.032 | 0.032 | 0.025 | 1.273 | 0.203 |
| INFRA -> ECOSY | 0.364*** | 0.365 | 0.013 | 27.703 | 0.000 |
| INFRA -> FARMI | 0.343*** | 0.342 | 0.016 | 21.066 | 0.000 |
| INFRA -> FOODENV | 0.234*** | 0.234 | 0.015 | 15.144 | 0.000 |
| ECOSY -> FARMI | 0.578*** | 0.577 | 0.015 | 37.708 | 0.000 |
| ECOSY -> CLIMA | -0.058** | -0.058 | 0.023 | -2.583 | 0.010 |
| FARMI -> FOODENV | 0.48*** | 0.480 | 0.014 | 34.098 | 0.000 |
| FARMI -> CLIMA | -0.126*** | -0.128 | 0.026 | -4.897 | 0.000 |
| FARMI -> NUTRI | -0.126*** | -0.126 | 0.018 | -6.958 | 0.000 |
| FARMI -> FOODSEC | 0.405*** | 0.405 | 0.012 | 33.749 | 0.000 |
| FOODENV -> CLIMA | 0.048*** | 0.048 | 0.015 | 3.105 | 0.002 |
| FOODENV -> NUTRI | -0.329*** | -0.329 | 0.018 | -18.744 | 0.000 |
| FOODENV -> FOODSEC | 0.473*** | 0.473 | 0.012 | 39.092 | 0.000 |
print_paths_tbl(
list(
"Main PLS-SEM" = list(
df = s_boot_full[["Main PLS-SEM"]]$bootstrapped_paths,
data = data_main
),
"Scenario A (Winsorization)" = list(
df = s_boot_full[["Scenario A"]]$bootstrapped_paths,
data = data_winsorize
),
"Scenario B (Deletion)" = list(
df = s_boot_full[["Scenario B"]]$bootstrapped_paths,
data = data_deletion
)
),
caption = "<b><span style='color:black'>Bootstrapped Path Coefficients - Full Model</span></b>"
)
| Path | Original Est. | Bootstrap Mean | Bootstrap SD | T Stat. | p-value |
|---|---|---|---|---|---|
| Main PLS-SEM | |||||
| ENVIR -> INFRA | -0.057** | -0.053 | 0.022 | -2.573 | 0.010 |
| ENVIR -> ECOSY | 0.029** | 0.026 | 0.014 | 2.025 | 0.043 |
| ENVIR -> FARMI | -0.013 | -0.012 | 0.012 | -1.140 | 0.254 |
| ENVIR -> FOODENV | 0.064*** | 0.058 | 0.022 | 2.978 | 0.003 |
| INFRA -> ECOSY | 0.393*** | 0.393 | 0.012 | 33.367 | 0.000 |
| INFRA -> FARMI | 0.382*** | 0.382 | 0.015 | 25.914 | 0.000 |
| INFRA -> FOODENV | 0.24*** | 0.239 | 0.015 | 16.061 | 0.000 |
| ECOSY -> FARMI | 0.534*** | 0.534 | 0.014 | 37.114 | 0.000 |
| ECOSY -> CLIMA | 0.002 | 0.002 | 0.030 | 0.053 | 0.958 |
| FARMI -> FOODENV | 0.449*** | 0.450 | 0.014 | 32.784 | 0.000 |
| FARMI -> CLIMA | -0.088*** | -0.089 | 0.022 | -3.907 | 0.000 |
| FARMI -> NUTRI | -0.171*** | -0.172 | 0.016 | -10.999 | 0.000 |
| FARMI -> FOODSEC | 0.407*** | 0.406 | 0.011 | 37.481 | 0.000 |
| FOODENV -> CLIMA | -0.034** | -0.034 | 0.017 | -2.030 | 0.042 |
| FOODENV -> NUTRI | -0.392*** | -0.392 | 0.014 | -27.467 | 0.000 |
| FOODENV -> FOODSEC | 0.481*** | 0.481 | 0.011 | 44.372 | 0.000 |
| Scenario A (Winsorization) | |||||
| ENVIR -> INFRA | -0.058** | -0.053 | 0.023 | -2.547 | 0.011 |
| ENVIR -> ECOSY | 0.029** | 0.026 | 0.015 | 1.991 | 0.046 |
| ENVIR -> FARMI | -0.01 | -0.009 | 0.012 | -0.884 | 0.377 |
| ENVIR -> FOODENV | 0.058*** | 0.053 | 0.021 | 2.785 | 0.005 |
| INFRA -> ECOSY | 0.393*** | 0.393 | 0.012 | 33.429 | 0.000 |
| INFRA -> FARMI | 0.378*** | 0.378 | 0.015 | 25.937 | 0.000 |
| INFRA -> FOODENV | 0.233*** | 0.232 | 0.015 | 15.647 | 0.000 |
| ECOSY -> FARMI | 0.544*** | 0.543 | 0.014 | 38.704 | 0.000 |
| ECOSY -> CLIMA | 0.014 | 0.014 | 0.032 | 0.441 | 0.659 |
| FARMI -> FOODENV | 0.461*** | 0.462 | 0.014 | 34.012 | 0.000 |
| FARMI -> CLIMA | -0.114*** | -0.116 | 0.025 | -4.590 | 0.000 |
| FARMI -> NUTRI | -0.174*** | -0.175 | 0.015 | -11.329 | 0.000 |
| FARMI -> FOODSEC | 0.409*** | 0.409 | 0.011 | 37.717 | 0.000 |
| FOODENV -> CLIMA | -0.02 | -0.020 | 0.015 | -1.327 | 0.185 |
| FOODENV -> NUTRI | -0.388*** | -0.389 | 0.014 | -27.102 | 0.000 |
| FOODENV -> FOODSEC | 0.478*** | 0.477 | 0.011 | 43.801 | 0.000 |
| Scenario B (Deletion) | |||||
| ENVIR -> INFRA | -0.073** | -0.064 | 0.029 | -2.531 | 0.011 |
| ENVIR -> ECOSY | 0.04* | 0.036 | 0.022 | 1.845 | 0.065 |
| ENVIR -> FARMI | -0.013 | -0.010 | 0.012 | -1.047 | 0.295 |
| ENVIR -> FOODENV | 0.032 | 0.032 | 0.026 | 1.250 | 0.211 |
| INFRA -> ECOSY | 0.365*** | 0.365 | 0.013 | 27.707 | 0.000 |
| INFRA -> FARMI | 0.344*** | 0.344 | 0.016 | 21.276 | 0.000 |
| INFRA -> FOODENV | 0.228*** | 0.227 | 0.016 | 14.668 | 0.000 |
| ECOSY -> FARMI | 0.573*** | 0.573 | 0.015 | 37.531 | 0.000 |
| ECOSY -> CLIMA | -0.058** | -0.057 | 0.023 | -2.561 | 0.010 |
| FARMI -> FOODENV | 0.485*** | 0.485 | 0.014 | 34.611 | 0.000 |
| FARMI -> CLIMA | -0.124*** | -0.126 | 0.026 | -4.878 | 0.000 |
| FARMI -> NUTRI | -0.196*** | -0.197 | 0.017 | -11.859 | 0.000 |
| FARMI -> FOODSEC | 0.406*** | 0.406 | 0.012 | 33.920 | 0.000 |
| FOODENV -> CLIMA | 0.043*** | 0.043 | 0.015 | 2.797 | 0.005 |
| FOODENV -> NUTRI | -0.376*** | -0.377 | 0.016 | -23.621 | 0.000 |
| FOODENV -> FOODSEC | 0.472*** | 0.472 | 0.012 | 38.919 | 0.000 |
plot(model_pls_iter2[["Main"]], title = "Structural model diagram - Main PLS-SEM (Refined Model)")
plot(model_pls_iter2[["ScenarioA"]], title = "Structural model diagram - Scenario A (Refined Model)")
plot(model_pls_iter2[["ScenarioB"]], title = "Structural model diagram - Scenario B (Refined Model)")
plot(model_pls_main, title = "Structural model diagram - Main PLS-SEM (Full Model)")
plot(model_pls_scenarioA, title = "Structural model diagram - Scenario A (Full Model)")
plot(model_pls_scenarioB, title = "Structural model diagram - Scenario B (Full Model)")
Total effects. Because indirect paths can attenuate, amplify, or flip the sign of direct effects, total effects (direct + indirect) provide the relevant substative interpretation of how upstream constructs influence downstream outcomes. Bootstrapped estimates (6,000 resemples) for the Refined and Full models indicate that most total effects are highly significant and consistent across robustness scenarios.
INFRA remais the
dominant sustemic driver, exerting strong positive total effects on
ECOSY, FARMI, FOODENV, and
FOODSEC. In contrast, its effects on CLIMA
(small) and NUTRI (high) are negative, implying that
INFRA improvements may trade off with nutritional or
environmental outcomes. ENVIR shows generally weak
influence, with a small and contrary negative effect on
INFRA and non-significant coefficients elsewhere.ECOSY maintais
strong, positive total effects on FARMI,
FOODENV, and FOODSEC, confirming it as a key
mediator linking upstream struture to downstream outcomes. Its effects
on CLIMA and NUTRI remain negative.
FARMI exerts large positive effects on FOODENV
and FOODSEC and small but systematic negative effects on
CLIMA and NUTRI, echoing the trade-offs
observed in formative indicators.FOODENV
consistently strengthens FOODSEC, validating its downstream
role, but its effects on CLIMA and NUTRI are
weak, unstable, or opposite to theoretical expectations (negative or
null in most scenarios and positive under listwise deletion. These
fluctuations suggest contextual sensitivity in how local food
environments interact with environmental and nutritional outcomes.In sum, the total effects confirm a coherent transmission chain
(INFRA -> ECOSY -> FARMI -> FOODENV -> FOODSEC)
that reproduces the hypothesized systemic pathways. Deviations for
CLIMA and NUTRI remain modest and
theoretically interpretable as structural trade-offs rather than model
misspecification.
total_summary <- tribble(
~Path, ~Summary,
"ENVIR -> INFRA", "Small but significant negative total effect (contrary to theory).",
"ENVIR -> ECOSY", "Small positive, consistent with theory but not significant.",
"ENVIR -> FARMI", "Non-significant, contrary to theory.",
"ENVIR -> FOODENV", "Small positive, non-significant; consistent with theory.",
"ENVIR -> CLIMA", "Null, consistent with theory.",
"ENVIR -> NUTRI", "Non-significant and contrary to theory.",
"ENVIR -> FOODSEC", "Mixed signs, not significant across scenarios.",
"INFRA -> ECOSY", "Strong positive, robust across scenarios.",
"INFRA -> FARMI", "Strong positive, robust across scenarios.",
"INFRA -> FOODENV", "Moderate-to-strong positive, robust across scenarios.",
"INFRA -> CLIMA", "Small negative, contrary to theory.",
"INFRA -> NUTRI", "Large negative, contrary to theory.",
"INFRA -> FOODSEC", "Strong positive, robust across scenarios.",
"ECOSY -> FARMI", "Strongest positive total effect robust.",
"ECOSY -> FOODENV", "Moderate positive, robust across scenarios.",
"ECOSY -> CLIMA", "Small negative, contrary to theory.",
"ECOSY -> NUTRI", "Moderate negative, contrary to theory.",
"ECOSY -> FOODSEC", "Moderate-to-strong positive, robust.",
"FARMI -> FOODENV", "Strong positive, robust across scenarios.",
"FARMI -> CLIMA", "Small negative, contrary to theory.",
"FARMI -> NUTRI", "Small-to-moderate negative contrary to theory.",
"FARMI -> FOODSEC", "Strong positive, robust across scenarios.",
"FOODENV -> CLIMA", "Mixed: weak negative to small positive depending on scenario.",
"FOODENV -> NUTRI", "Consistently negative, contrary to theory.",
"FOODENV -> FOODSEC", "Strong positive, robust across scenarios."
)
kable(total_summary,
format = "html",
caption = "<b><span style='color:black'>Summary of Total Effects (Refined and Full Models)</span></b>",
escape = FALSE, booktabs = TRUE,
col.names = c("Path (theory: positive)", "Summary of empirical results")) %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE, position = "center", fixed_thead = TRUE)
| Path (theory: positive) | Summary of empirical results |
|---|---|
| ENVIR -> INFRA | Small but significant negative total effect (contrary to theory). |
| ENVIR -> ECOSY | Small positive, consistent with theory but not significant. |
| ENVIR -> FARMI | Non-significant, contrary to theory. |
| ENVIR -> FOODENV | Small positive, non-significant; consistent with theory. |
| ENVIR -> CLIMA | Null, consistent with theory. |
| ENVIR -> NUTRI | Non-significant and contrary to theory. |
| ENVIR -> FOODSEC | Mixed signs, not significant across scenarios. |
| INFRA -> ECOSY | Strong positive, robust across scenarios. |
| INFRA -> FARMI | Strong positive, robust across scenarios. |
| INFRA -> FOODENV | Moderate-to-strong positive, robust across scenarios. |
| INFRA -> CLIMA | Small negative, contrary to theory. |
| INFRA -> NUTRI | Large negative, contrary to theory. |
| INFRA -> FOODSEC | Strong positive, robust across scenarios. |
| ECOSY -> FARMI | Strongest positive total effect robust. |
| ECOSY -> FOODENV | Moderate positive, robust across scenarios. |
| ECOSY -> CLIMA | Small negative, contrary to theory. |
| ECOSY -> NUTRI | Moderate negative, contrary to theory. |
| ECOSY -> FOODSEC | Moderate-to-strong positive, robust. |
| FARMI -> FOODENV | Strong positive, robust across scenarios. |
| FARMI -> CLIMA | Small negative, contrary to theory. |
| FARMI -> NUTRI | Small-to-moderate negative contrary to theory. |
| FARMI -> FOODSEC | Strong positive, robust across scenarios. |
| FOODENV -> CLIMA | Mixed: weak negative to small positive depending on scenario. |
| FOODENV -> NUTRI | Consistently negative, contrary to theory. |
| FOODENV -> FOODSEC | Strong positive, robust across scenarios. |
print_paths_tbl( list( "Main PLS-SEM" = list( df = s_boot_refined[["Main PLS-SEM"]]$bootstrapped_total_paths,
data = data_main
),
"Scenario A (Winsorization)" = list(
df = s_boot_refined[["Scenario A"]]$bootstrapped_total_paths, data = data_winsorize ), "Scenario B (Deletion)" = list( df = s_boot_refined[["Scenario B"]]$bootstrapped_total_paths, data = data_deletion ) ), caption = "<b>Bootstrapped Total Effects - Refined Model</b>" )
| Path | Original Est. | Bootstrap Mean | Bootstrap SD | T Stat. | p-value |
|---|---|---|---|---|---|
| Main PLS-SEM | |||||
| ENVIR -> INFRA | -0.057*** | -0.054 | 0.022 | -2.640 | 0.008 |
| ENVIR -> ECOSY | 0.007 | 0.005 | 0.016 | 0.418 | 0.676 |
| ENVIR -> FARMI | -0.032 | -0.030 | 0.022 | -1.402 | 0.161 |
| ENVIR -> FOODENV | 0.037 | 0.033 | 0.028 | 1.327 | 0.185 |
| ENVIR -> CLIMA | 0.001 | 0.001 | 0.003 | 0.497 | 0.619 |
| ENVIR -> NUTRI | -0.01 | -0.010 | 0.011 | -0.888 | 0.375 |
| ENVIR -> FOODSEC | 0.005 | 0.005 | 0.021 | 0.252 | 0.801 |
| INFRA -> ECOSY | 0.392*** | 0.393 | 0.012 | 33.354 | 0.000 |
| INFRA -> FARMI | 0.592*** | 0.592 | 0.011 | 55.332 | 0.000 |
| INFRA -> FOODENV | 0.509*** | 0.509 | 0.011 | 47.082 | 0.000 |
| INFRA -> CLIMA | -0.067*** | -0.068 | 0.012 | -5.807 | 0.000 |
| INFRA -> NUTRI | -0.236*** | -0.236 | 0.009 | -26.376 | 0.000 |
| INFRA -> FOODSEC | 0.486*** | 0.486 | 0.009 | 54.405 | 0.000 |
| ECOSY -> FARMI | 0.538*** | 0.538 | 0.014 | 37.126 | 0.000 |
| ECOSY -> FOODENV | 0.238*** | 0.239 | 0.010 | 23.805 | 0.000 |
| ECOSY -> CLIMA | -0.054** | -0.055 | 0.024 | -2.276 | 0.023 |
| ECOSY -> NUTRI | -0.136*** | -0.136 | 0.009 | -15.209 | 0.000 |
| ECOSY -> FOODSEC | 0.333*** | 0.333 | 0.010 | 34.906 | 0.000 |
| FARMI -> FOODENV | 0.443*** | 0.444 | 0.014 | 32.101 | 0.000 |
| FARMI -> CLIMA | -0.1*** | -0.101 | 0.023 | -4.339 | 0.000 |
| FARMI -> NUTRI | -0.252*** | -0.253 | 0.014 | -17.500 | 0.000 |
| FARMI -> FOODSEC | 0.619*** | 0.619 | 0.010 | 64.044 | 0.000 |
| FOODENV -> CLIMA | -0.033* | -0.033 | 0.017 | -1.941 | 0.052 |
| FOODENV -> NUTRI | -0.351*** | -0.351 | 0.015 | -22.853 | 0.000 |
| FOODENV -> FOODSEC | 0.482*** | 0.482 | 0.011 | 44.701 | 0.000 |
| Scenario A (Winsorization) | |||||
| ENVIR -> INFRA | -0.058** | -0.054 | 0.022 | -2.590 | 0.010 |
| ENVIR -> ECOSY | 0.007 | 0.005 | 0.017 | 0.402 | 0.688 |
| ENVIR -> FARMI | -0.029 | -0.027 | 0.023 | -1.232 | 0.218 |
| ENVIR -> FOODENV | 0.033 | 0.029 | 0.028 | 1.150 | 0.250 |
| ENVIR -> CLIMA | 0.003 | 0.002 | 0.003 | 0.866 | 0.386 |
| ENVIR -> NUTRI | -0.008 | -0.008 | 0.012 | -0.722 | 0.470 |
| ENVIR -> FOODSEC | 0.004 | 0.004 | 0.021 | 0.187 | 0.851 |
| INFRA -> ECOSY | 0.393*** | 0.393 | 0.012 | 33.417 | 0.000 |
| INFRA -> FARMI | 0.592*** | 0.592 | 0.011 | 56.224 | 0.000 |
| INFRA -> FOODENV | 0.509*** | 0.509 | 0.011 | 47.163 | 0.000 |
| INFRA -> CLIMA | -0.071*** | -0.072 | 0.011 | -6.417 | 0.000 |
| INFRA -> NUTRI | -0.236*** | -0.236 | 0.009 | -26.635 | 0.000 |
| INFRA -> FOODSEC | 0.485*** | 0.485 | 0.009 | 54.690 | 0.000 |
| ECOSY -> FARMI | 0.548*** | 0.547 | 0.014 | 38.835 | 0.000 |
| ECOSY -> FOODENV | 0.249*** | 0.249 | 0.010 | 24.708 | 0.000 |
| ECOSY -> CLIMA | -0.054** | -0.054 | 0.024 | -2.221 | 0.026 |
| ECOSY -> NUTRI | -0.142*** | -0.142 | 0.009 | -15.841 | 0.000 |
| ECOSY -> FOODSEC | 0.343*** | 0.343 | 0.009 | 36.142 | 0.000 |
| FARMI -> FOODENV | 0.455*** | 0.456 | 0.014 | 33.335 | 0.000 |
| FARMI -> CLIMA | -0.121*** | -0.123 | 0.025 | -4.791 | 0.000 |
| FARMI -> NUTRI | -0.259*** | -0.260 | 0.014 | -18.269 | 0.000 |
| FARMI -> FOODSEC | 0.626*** | 0.626 | 0.010 | 65.787 | 0.000 |
| FOODENV -> CLIMA | -0.019 | -0.018 | 0.016 | -1.195 | 0.232 |
| FOODENV -> NUTRI | -0.345*** | -0.344 | 0.015 | -22.234 | 0.000 |
| FOODENV -> FOODSEC | 0.479*** | 0.479 | 0.011 | 44.145 | 0.000 |
| Scenario B (Deletion) | |||||
| ENVIR -> INFRA | -0.073** | -0.065 | 0.028 | -2.579 | 0.010 |
| ENVIR -> ECOSY | 0.013 | 0.012 | 0.023 | 0.581 | 0.562 |
| ENVIR -> FARMI | -0.03 | -0.026 | 0.027 | -1.118 | 0.264 |
| ENVIR -> FOODENV | 0.001 | 0.004 | 0.037 | 0.018 | 0.986 |
| ENVIR -> CLIMA | 0.003 | 0.003 | 0.003 | 0.916 | 0.360 |
| ENVIR -> NUTRI | 0.004 | 0.002 | 0.015 | 0.238 | 0.812 |
| ENVIR -> FOODSEC | -0.012 | -0.009 | 0.027 | -0.438 | 0.661 |
| INFRA -> ECOSY | 0.364*** | 0.365 | 0.013 | 27.703 | 0.000 |
| INFRA -> FARMI | 0.553*** | 0.553 | 0.012 | 44.925 | 0.000 |
| INFRA -> FOODENV | 0.5*** | 0.500 | 0.012 | 41.381 | 0.000 |
| INFRA -> CLIMA | -0.067*** | -0.068 | 0.012 | -5.629 | 0.000 |
| INFRA -> NUTRI | -0.234*** | -0.234 | 0.009 | -25.549 | 0.000 |
| INFRA -> FOODSEC | 0.46*** | 0.460 | 0.010 | 45.497 | 0.000 |
| ECOSY -> FARMI | 0.578*** | 0.577 | 0.015 | 37.708 | 0.000 |
| ECOSY -> FOODENV | 0.277*** | 0.277 | 0.011 | 24.363 | 0.000 |
| ECOSY -> CLIMA | -0.118*** | -0.119 | 0.019 | -6.115 | 0.000 |
| ECOSY -> NUTRI | -0.164*** | -0.164 | 0.010 | -16.344 | 0.000 |
| ECOSY -> FOODSEC | 0.365*** | 0.365 | 0.010 | 34.972 | 0.000 |
| FARMI -> FOODENV | 0.48*** | 0.480 | 0.014 | 34.098 | 0.000 |
| FARMI -> CLIMA | -0.103*** | -0.105 | 0.025 | -4.077 | 0.000 |
| FARMI -> NUTRI | -0.283*** | -0.284 | 0.015 | -18.975 | 0.000 |
| FARMI -> FOODSEC | 0.632*** | 0.632 | 0.010 | 65.072 | 0.000 |
| FOODENV -> CLIMA | 0.048*** | 0.048 | 0.015 | 3.105 | 0.002 |
| FOODENV -> NUTRI | -0.329*** | -0.329 | 0.018 | -18.744 | 0.000 |
| FOODENV -> FOODSEC | 0.473*** | 0.473 | 0.012 | 39.092 | 0.000 |
print_paths_tbl( list( "Main PLS-SEM" = list( df = s_boot_full[["Main PLS-SEM"]]$bootstrapped_total_paths,
data = data_main
),
"Scenario A (Winsorization)" = list(
df = s_boot_full[["Scenario A"]]$bootstrapped_total_paths, data = data_winsorize ), "Scenario B (Deletion)" = list( df = s_boot_full[["Scenario B"]]$bootstrapped_total_paths, data = data_deletion ) ), caption = "<b><span style='color:black'>Bootstrapped Total Effects - Full Model<span></b>" )
| Path | Original Est. | Bootstrap Mean | Bootstrap SD | T Stat. | p-value |
|---|---|---|---|---|---|
| Main PLS-SEM | |||||
| ENVIR -> INFRA | -0.057** | -0.053 | 0.022 | -2.573 | 0.010 |
| ENVIR -> ECOSY | 0.007 | 0.005 | 0.017 | 0.415 | 0.678 |
| ENVIR -> FARMI | -0.031 | -0.030 | 0.023 | -1.365 | 0.172 |
| ENVIR -> FOODENV | 0.036 | 0.032 | 0.029 | 1.250 | 0.211 |
| ENVIR -> CLIMA | 0.001 | 0.001 | 0.003 | 0.438 | 0.661 |
| ENVIR -> NUTRI | -0.011 | -0.009 | 0.014 | -0.783 | 0.434 |
| ENVIR -> FOODSEC | 0.007 | 0.005 | 0.021 | 0.350 | 0.727 |
| INFRA -> ECOSY | 0.393*** | 0.393 | 0.012 | 33.367 | 0.000 |
| INFRA -> FARMI | 0.591*** | 0.591 | 0.011 | 55.602 | 0.000 |
| INFRA -> FOODENV | 0.505*** | 0.505 | 0.011 | 46.480 | 0.000 |
| INFRA -> CLIMA | -0.068*** | -0.069 | 0.012 | -5.930 | 0.000 |
| INFRA -> NUTRI | -0.299*** | -0.300 | 0.009 | -35.157 | 0.000 |
| INFRA -> FOODSEC | 0.483*** | 0.483 | 0.009 | 54.129 | 0.000 |
| ECOSY -> FARMI | 0.534*** | 0.534 | 0.014 | 37.114 | 0.000 |
| ECOSY -> FOODENV | 0.24*** | 0.240 | 0.010 | 24.124 | 0.000 |
| ECOSY -> CLIMA | -0.053** | -0.054 | 0.024 | -2.250 | 0.025 |
| ECOSY -> NUTRI | -0.185*** | -0.186 | 0.009 | -20.887 | 0.000 |
| ECOSY -> FOODSEC | 0.332*** | 0.332 | 0.010 | 34.938 | 0.000 |
| FARMI -> FOODENV | 0.449*** | 0.450 | 0.014 | 32.784 | 0.000 |
| FARMI -> CLIMA | -0.103*** | -0.105 | 0.023 | -4.490 | 0.000 |
| FARMI -> NUTRI | -0.347*** | -0.348 | 0.014 | -25.664 | 0.000 |
| FARMI -> FOODSEC | 0.623*** | 0.623 | 0.010 | 64.740 | 0.000 |
| FOODENV -> CLIMA | -0.034** | -0.034 | 0.017 | -2.030 | 0.042 |
| FOODENV -> NUTRI | -0.392*** | -0.392 | 0.014 | -27.467 | 0.000 |
| FOODENV -> FOODSEC | 0.481*** | 0.481 | 0.011 | 44.372 | 0.000 |
| Scenario A (Winsorization) | |||||
| ENVIR -> INFRA | -0.058** | -0.053 | 0.023 | -2.547 | 0.011 |
| ENVIR -> ECOSY | 0.007 | 0.005 | 0.017 | 0.397 | 0.691 |
| ENVIR -> FARMI | -0.029 | -0.027 | 0.023 | -1.219 | 0.223 |
| ENVIR -> FOODENV | 0.032 | 0.028 | 0.029 | 1.092 | 0.275 |
| ENVIR -> CLIMA | 0.003 | 0.002 | 0.003 | 0.807 | 0.420 |
| ENVIR -> NUTRI | -0.01 | -0.008 | 0.014 | -0.672 | 0.502 |
| ENVIR -> FOODSEC | 0.006 | 0.004 | 0.021 | 0.290 | 0.772 |
| INFRA -> ECOSY | 0.393*** | 0.393 | 0.012 | 33.429 | 0.000 |
| INFRA -> FARMI | 0.592*** | 0.592 | 0.010 | 56.475 | 0.000 |
| INFRA -> FOODENV | 0.506*** | 0.506 | 0.011 | 46.554 | 0.000 |
| INFRA -> CLIMA | -0.072*** | -0.073 | 0.011 | -6.528 | 0.000 |
| INFRA -> NUTRI | -0.299*** | -0.300 | 0.008 | -35.442 | 0.000 |
| INFRA -> FOODSEC | 0.483*** | 0.483 | 0.009 | 54.427 | 0.000 |
| ECOSY -> FARMI | 0.544*** | 0.543 | 0.014 | 38.704 | 0.000 |
| ECOSY -> FOODENV | 0.251*** | 0.251 | 0.010 | 25.038 | 0.000 |
| ECOSY -> CLIMA | -0.053** | -0.054 | 0.024 | -2.197 | 0.028 |
| ECOSY -> NUTRI | -0.192*** | -0.193 | 0.009 | -21.715 | 0.000 |
| ECOSY -> FOODSEC | 0.342*** | 0.342 | 0.009 | 36.126 | 0.000 |
| FARMI -> FOODENV | 0.461*** | 0.462 | 0.014 | 34.012 | 0.000 |
| FARMI -> CLIMA | -0.123*** | -0.125 | 0.025 | -4.908 | 0.000 |
| FARMI -> NUTRI | -0.353*** | -0.354 | 0.013 | -26.790 | 0.000 |
| FARMI -> FOODSEC | 0.629*** | 0.629 | 0.009 | 66.461 | 0.000 |
| FOODENV -> CLIMA | -0.02 | -0.020 | 0.015 | -1.327 | 0.185 |
| FOODENV -> NUTRI | -0.388*** | -0.389 | 0.014 | -27.102 | 0.000 |
| FOODENV -> FOODSEC | 0.478*** | 0.477 | 0.011 | 43.801 | 0.000 |
| Scenario B (Deletion) | |||||
| ENVIR -> INFRA | -0.073** | -0.064 | 0.029 | -2.531 | 0.011 |
| ENVIR -> ECOSY | 0.013 | 0.012 | 0.023 | 0.576 | 0.564 |
| ENVIR -> FARMI | -0.03 | -0.026 | 0.027 | -1.108 | 0.268 |
| ENVIR -> FOODENV | 0.001 | 0.005 | 0.038 | 0.024 | 0.981 |
| ENVIR -> CLIMA | 0.003 | 0.003 | 0.003 | 0.884 | 0.377 |
| ENVIR -> NUTRI | 0.006 | 0.003 | 0.019 | 0.299 | 0.765 |
| ENVIR -> FOODSEC | -0.012 | -0.008 | 0.028 | -0.432 | 0.666 |
| INFRA -> ECOSY | 0.365*** | 0.365 | 0.013 | 27.707 | 0.000 |
| INFRA -> FARMI | 0.553*** | 0.554 | 0.012 | 45.273 | 0.000 |
| INFRA -> FOODENV | 0.496*** | 0.496 | 0.012 | 40.839 | 0.000 |
| INFRA -> CLIMA | -0.069*** | -0.069 | 0.012 | -5.766 | 0.000 |
| INFRA -> NUTRI | -0.295*** | -0.296 | 0.009 | -33.312 | 0.000 |
| INFRA -> FOODSEC | 0.459*** | 0.459 | 0.010 | 45.373 | 0.000 |
| ECOSY -> FARMI | 0.573*** | 0.573 | 0.015 | 37.531 | 0.000 |
| ECOSY -> FOODENV | 0.278*** | 0.278 | 0.011 | 24.551 | 0.000 |
| ECOSY -> CLIMA | -0.117*** | -0.118 | 0.019 | -6.070 | 0.000 |
| ECOSY -> NUTRI | -0.217*** | -0.217 | 0.010 | -21.935 | 0.000 |
| ECOSY -> FOODSEC | 0.364*** | 0.364 | 0.010 | 34.836 | 0.000 |
| FARMI -> FOODENV | 0.485*** | 0.485 | 0.014 | 34.611 | 0.000 |
| FARMI -> CLIMA | -0.104*** | -0.105 | 0.025 | -4.126 | 0.000 |
| FARMI -> NUTRI | -0.378*** | -0.379 | 0.014 | -27.820 | 0.000 |
| FARMI -> FOODSEC | 0.635*** | 0.635 | 0.010 | 65.707 | 0.000 |
| FOODENV -> CLIMA | 0.043*** | 0.043 | 0.015 | 2.797 | 0.005 |
| FOODENV -> NUTRI | -0.376*** | -0.377 | 0.016 | -23.621 | 0.000 |
| FOODENV -> FOODSEC | 0.472*** | 0.472 | 0.012 | 38.919 | 0.000 |
Explanatory power. \(R^2\) values assess the model’s explanatory strength, with thresholds of 0.75, 0.5 and 0.25 indicate substantial, moderate, and weak power, respectively. Effect sizes \(f^2\) quantify the relative contribution of each exogenous construct, with 0.35, 0.15, and 0.02 representing large, medium, and small effects.
FARMI and FOODSEC show substantial
explanatory power (approx. 0.60), while FOODENV is moderate
(approx. 0.40). ECOSY and NUTRI are
weak-to-moderate (approx. 0.15 to 0.26), and CLIMA and
INFRA remain exogenous (below 0.05). Large \(f^2\) effects occur for
ECOSY -> FARMI, FARMI -> FOODENV, and
FOODENV -> FOODSEC, confirming that FARMI
and FOODENV are central conduits through which upstream
constructs (e.g., INFRA, ECOSY) influence
FOODSEC outcomes.
tidy_r2 <- function(s, label, which = "R^2"){
p <- s$paths
df <- as.data.frame(p, stringsAsFactors = FALSE)
stopifnot(!is.null(rownames(df)), !is.null(colnames(df)))
stopifnot(which %in% rownames(df))
row <- df[which, , drop = TRUE]
tibble(Construct = names(row),
!!label := suppressWarnings(as.numeric(row))) %>%
filter(!is.na(!!sym(label))) }
format_r2 <- function(x, digits = 3, bold_thr = 0.25){
out <- rep("-", length(x))
not_na <- !is.na(x)
if (any(not_na)){
base <- sprintf(paste0("%.", digits, "f"), x[not_na])
out[not_na] <- base
bold_idx <- x[not_na] >= bold_thr
out[not_na][bold_idx] <- cell_spec(base[bold_idx], bold = TRUE)
}
out
}
num_cols_r2 <- c("Main sample", "Scenario A (Winsorized)", "Scenario B (Deletion)")
r2_refined <- tidy_r2(s_main_iter2, "Main sample") %>%
full_join(tidy_r2(s_A_iter2, "Scenario A (Winsorized)"), by = "Construct") %>%
full_join(tidy_r2(s_B_iter2, "Scenario B (Deletion)"), by = "Construct") %>%
arrange(Construct) %>%
mutate(across(all_of(num_cols_r2), ~ suppressWarnings(as.numeric(.x)))) %>%
mutate(across(all_of(num_cols_r2), ~ format_r2(.x, digits = 3, bold_thr = 0.25)))
r2_full <- tidy_r2(s_main, "Main sample") %>%
full_join(tidy_r2(s_A, "Scenario A (Winsorized)"), by = "Construct") %>%
full_join(tidy_r2(s_B, "Scenario B (Deletion)"), by = "Construct") %>%
arrange(Construct) %>%
mutate(across(all_of(num_cols_r2), ~ suppressWarnings(as.numeric(.x)))) %>%
mutate(across(all_of(num_cols_r2), ~ format_r2(.x, digits = 3, bold_thr = 0.25)))
r2_combined <- bind_rows(
r2_refined %>% mutate(Model = "Refined Model"),
r2_full %>% mutate(Model = "Full Model")
)
kbl(r2_combined %>%
select(Construct, all_of(num_cols_r2)),
format = "html", escape = FALSE,
booktabs = TRUE,
align = c("l", "l", rep("c", length(num_cols_r2))),
caption = paste0("<b><span style='color:black'>$R^2$ of endogenous constructs - Refined and Full Models<span></b><br>",
"Bold indicates $R^2 \\geq 0.25$.")
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE, position = "center", fixed_thead = TRUE
) %>%
pack_rows("Refined Model", 1, nrow(r2_refined)) %>%
pack_rows("Full Model", nrow(r2_refined)+1, nrow(r2_combined))
| Construct | Main sample | Scenario A (Winsorized) | Scenario B (Deletion) |
|---|---|---|---|
| Refined Model | |||
| CLIMA | 0.012 | 0.013 | 0.022 |
| ECOSY | 0.154 | 0.154 | 0.132 |
| FARMI | 0.596 | 0.604 | 0.595 |
| FOODENV | 0.387 | 0.394 | 0.408 |
| FOODSEC | 0.626 | 0.628 | 0.621 |
| INFRA | 0.003 | 0.003 | 0.005 |
| NUTRI | 0.172 | 0.171 | 0.174 |
| Full Model | |||
| CLIMA | 0.012 | 0.014 | 0.022 |
| ECOSY | 0.154 | 0.154 | 0.132 |
| FARMI | 0.591 | 0.600 | 0.591 |
| FOODENV | 0.387 | 0.394 | 0.408 |
| FOODSEC | 0.627 | 0.628 | 0.621 |
| INFRA | 0.003 | 0.003 | 0.005 |
| NUTRI | 0.262 | 0.262 | 0.270 |
f2_list <- list(
"Main sample" = s_main_iter2$fSquare,
"Scenario A" = s_A_iter2$fSquare,
"Scenario B" = s_B_iter2$fSquare
)
format_f2 <- function(x, digits = 3, bold_thr = 0.15) {
x <- suppressWarnings(as.numeric(x))
formatted <- ifelse(is.na(x), "", formatC(x, digits = digits, format = "f"))
formatted <- ifelse(
!is.na(x) & x >= bold_thr,
paste0("<b>", formatted, "</b>"),
formatted)
formatted
}
f2_panel_table <- function(f2_list,
digits = 3, bold_thr = 0.15,
caption_prefix =
"<b><span style='color:black'>$f^2$ effect sizes - Refined Model ") {
constructs <- colnames(as.data.frame(f2_list[[1]], check.names = FALSE))
panel_df <- imap_dfr(f2_list, function(mat, scen) {
m <- as.matrix(mat)
m[m < 0] <- 0
keep <- row(m) <= col(m)
m[!keep] <- NA
as.data.frame(m, check.names = FALSE) %>%
rownames_to_column(var = "Construct") %>%
mutate(Scenario = scen) %>%
relocate(Scenario, Construct, all_of(constructs))
})
num_cols <- setdiff(names(panel_df), c("Scenario","Construct"))
panel_df[num_cols] <- lapply(panel_df[num_cols], format_f2,
digits = digits, bold_thr = bold_thr)
panel_df <- panel_df %>%
mutate(Construct = factor(Construct, levels = constructs, ordered = TRUE)) %>%
arrange(Scenario, Construct)
idx <- panel_df %>%
mutate(row_id = row_number()) %>%
group_by(Scenario) %>%
summarise(start = min(row_id), end = max(row_id), .groups = "drop")
kb <- kable(
panel_df %>%
select(-Scenario),
format = "html",
escape = FALSE,
align = c("l", rep("r", length(num_cols))),
caption = paste0(
caption_prefix, "<span></b><br>",
"Bold indicates $f^2 \\geq 0.15$."
)
) %>%
kable_styling(
bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE, position = "center", fixed_thead = TRUE
)
if (nrow(idx) > 0) {
for (i in seq_len(nrow(idx))) {
kb <- kb %>%
group_rows(idx$Scenario[i], idx$start[i], idx$end[i], bold = TRUE)
}
}
kb
}
f2_panel_table(f2_list,
digits = 3,
bold_thr = 0.15
)
| Construct | ENVIR | INFRA | ECOSY | FARMI | FOODENV | CLIMA | NUTRI | FOODSEC |
|---|---|---|---|---|---|---|---|---|
| Main sample | ||||||||
| ENVIR | 0.000 | 0.003 | 0.001 | 0.000 | 0.005 | 0.000 | 0.000 | 0.000 |
| INFRA | 0.000 | 0.181 | 0.189 | 0.066 | 0.000 | 0.000 | 0.000 | |
| ECOSY | 0.000 | 0.489 | 0.000 | 0.000 | 0.000 | 0.000 | ||
| FARMI | 0.000 | 0.202 | 0.003 | 0.008 | 0.290 | |||
| FOODENV | 0.000 | 0.001 | 0.097 | 0.410 | ||||
| CLIMA | 0.000 | 0.000 | 0.000 | |||||
| NUTRI | 0.000 | 0.000 | ||||||
| FOODSEC | 0.000 | |||||||
| Scenario A | ||||||||
| ENVIR | 0.000 | 0.003 | 0.001 | 0.000 | 0.005 | 0.000 | 0.000 | 0.000 |
| INFRA | 0.000 | 0.181 | 0.195 | 0.063 | 0.000 | 0.000 | 0.000 | |
| ECOSY | 0.000 | 0.518 | 0.000 | 0.000 | 0.000 | 0.000 | ||
| FARMI | 0.000 | 0.215 | 0.005 | 0.008 | 0.290 | |||
| FOODENV | 0.000 | 0.000 | 0.092 | 0.399 | ||||
| CLIMA | 0.000 | 0.000 | 0.000 | |||||
| NUTRI | 0.000 | 0.000 | ||||||
| FOODSEC | 0.000 | |||||||
| Scenario B | ||||||||
| ENVIR | 0.000 | 0.005 | 0.002 | 0.000 | 0.002 | 0.000 | 0.000 | 0.000 |
| INFRA | 0.000 | 0.152 | 0.158 | 0.065 | 0.000 | 0.000 | 0.000 | |
| ECOSY | 0.000 | 0.580 | 0.000 | 0.002 | 0.000 | 0.000 | ||
| FARMI | 0.000 | 0.260 | 0.007 | 0.012 | 0.273 | |||
| FOODENV | 0.000 | 0.002 | 0.081 | 0.372 | ||||
| CLIMA | 0.000 | 0.000 | 0.000 | |||||
| NUTRI | 0.000 | 0.000 | ||||||
| FOODSEC | 0.000 | |||||||
f2_list <- list(
"Main sample" = s_main$fSquare,
"Scenario A" = s_A$fSquare,
"Scenario B" = s_B$fSquare
)
f2_panel_table <- function(f2_list,
digits = 3, bold_thr = 0.15,
caption_prefix =
"<b><span style='color:black'>$f^2$ effect sizes - Full Model ") {
constructs <- colnames(as.data.frame(f2_list[[1]], check.names = FALSE))
panel_df <- imap_dfr(f2_list, function(mat, scen) {
m <- as.matrix(mat)
m[m < 0] <- 0
keep <- row(m) <= col(m)
m[!keep] <- NA
as.data.frame(m, check.names = FALSE) %>%
rownames_to_column(var = "Construct") %>%
mutate(Scenario = scen) %>%
relocate(Scenario, Construct, all_of(constructs))
})
num_cols <- setdiff(names(panel_df), c("Scenario","Construct"))
panel_df[num_cols] <- lapply(panel_df[num_cols], format_f2,
digits = digits, bold_thr = bold_thr)
panel_df <- panel_df %>%
mutate(Construct = factor(Construct, levels = constructs, ordered = TRUE)) %>%
arrange(Scenario, Construct)
idx <- panel_df %>%
mutate(row_id = row_number()) %>%
group_by(Scenario) %>%
summarise(start = min(row_id), end = max(row_id), .groups = "drop")
kb <- kable(
panel_df %>%
select(-Scenario),
format = "html",
escape = FALSE,
align = c("l", rep("r", length(num_cols))),
caption = paste0(
caption_prefix, "<span></b><br>",
"Bold indicates $f^2 \\geq 0.15$."
)
) %>%
kable_styling(
bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE, position = "center", fixed_thead = TRUE
)
if (nrow(idx) > 0) {
for (i in seq_len(nrow(idx))) {
kb <- kb %>%
group_rows(idx$Scenario[i], idx$start[i], idx$end[i], bold = TRUE)
}
}
kb
}
f2_panel_table(f2_list,
digits = 3,
bold_thr = 0.15
)
| Construct | ENVIR | INFRA | ECOSY | FARMI | FOODENV | CLIMA | NUTRI | FOODSEC |
|---|---|---|---|---|---|---|---|---|
| Main sample | ||||||||
| ENVIR | 0.000 | 0.003 | 0.001 | 0.000 | 0.005 | 0.000 | 0.000 | 0.000 |
| INFRA | 0.000 | 0.182 | 0.194 | 0.063 | 0.000 | 0.000 | 0.000 | |
| ECOSY | 0.000 | 0.484 | 0.000 | 0.000 | 0.000 | 0.000 | ||
| FARMI | 0.000 | 0.209 | 0.003 | 0.026 | 0.290 | |||
| FOODENV | 0.000 | 0.001 | 0.134 | 0.407 | ||||
| CLIMA | 0.000 | 0.000 | 0.000 | |||||
| NUTRI | 0.000 | 0.000 | ||||||
| FOODSEC | 0.000 | |||||||
| Scenario A | ||||||||
| ENVIR | 0.000 | 0.003 | 0.001 | 0.000 | 0.005 | 0.000 | 0.000 | 0.000 |
| INFRA | 0.000 | 0.182 | 0.199 | 0.061 | 0.000 | 0.000 | 0.000 | |
| ECOSY | 0.000 | 0.514 | 0.000 | 0.000 | 0.000 | 0.000 | ||
| FARMI | 0.000 | 0.222 | 0.006 | 0.026 | 0.290 | |||
| FOODENV | 0.000 | 0.000 | 0.130 | 0.396 | ||||
| CLIMA | 0.000 | 0.000 | 0.000 | |||||
| NUTRI | 0.000 | 0.000 | ||||||
| FOODSEC | 0.000 | |||||||
| Scenario B | ||||||||
| ENVIR | 0.000 | 0.005 | 0.002 | 0.000 | 0.002 | 0.000 | 0.000 | 0.000 |
| INFRA | 0.000 | 0.152 | 0.163 | 0.062 | 0.000 | 0.000 | 0.000 | |
| ECOSY | 0.000 | 0.575 | 0.000 | 0.002 | 0.000 | 0.000 | ||
| FARMI | 0.000 | 0.266 | 0.006 | 0.033 | 0.274 | |||
| FOODENV | 0.000 | 0.001 | 0.120 | 0.370 | ||||
| CLIMA | 0.000 | 0.000 | 0.000 | |||||
| NUTRI | 0.000 | 0.000 | ||||||
| FOODSEC | 0.000 | |||||||
Predictive power. Out-of-sample predictive was assessed with PLSpredict using the Direct Antecedents scheme and 10-fold cross-validation with 10 repetitions across all specifications (Refined and Full models) and scenarios (Main, Scenario A, and Scenario B). A linear model (LM) served as benchmark, and indicator-level RMSE and MAE were computed for in- and out-of-sample data. The tables below report PLS/LM error ratios (ratio less than 1 favors PLS; greater than 1 favors LM).
Overall, LM predicts better than PLS-SEM for most indicators and
scenarios: the PLS/LM ratios are typically above 1, with differences
concentrated around +5% to +25%, and occasional larger gaps near +30%
for INFRA and sobre ECOSY indicators.
Close-to-parity cases (ratios approx. 1.05) appear for a few items
(e.g., ecosy_3 (ii1), farmi_8 (v4),
foodenv_3 (n2)), and this pattern is stable across Main,
Scenario A and Scenario B as well as between Refined and Full models.
For outcomes like foodsec and clima, PLS error
are generally about 10% to 20% higher than LM. Taken together, the
models show limited incremental predictive advantage of PLS-SEM over a
simple LM baseline.
run_predict <- function(model, folds = 10, reps = 10) {
out <- predict_pls(model, technique = predict_DA, noFolds = folds, reps = reps)
summary(out)
}
models_refined <- list(
"Main sample" = model_pls_iter2$Main,
"Scenario A" = model_pls_iter2$ScenarioA,
"Scenario B" = model_pls_iter2$ScenarioB
)
models_full <- list(
"Main sample" = model_pls_main,
"Scenario A" = model_pls_scenarioA,
"Scenario B" = model_pls_scenarioB
)
s_predict_refined <- lapply(models_refined, run_predict)
s_predict_full <- lapply(models_full, run_predict)
tidy_metrics <- function(mat, scenario, model, sample){
as.data.frame(mat, check.names = FALSE) %>%
rownames_to_column("metric") %>%
pivot_longer(-metric, names_to = "indicator", values_to = "value") %>%
mutate(scenario = scenario, model = model, sample = sample)
}
tidy_from_scenario <- function(x_sce, sce_name){
bind_rows(
tidy_metrics(x_sce$PLS_in_sample, sce_name, "PLS", "in"),
tidy_metrics(x_sce$PLS_out_of_sample, sce_name, "PLS", "out"),
tidy_metrics(x_sce$LM_in_sample, sce_name, "LM", "in"),
tidy_metrics(x_sce$LM_out_of_sample, sce_name, "LM", "out")
)
}
tidy_from_root <- function(obj_root){
imap_dfr(obj_root, ~ tidy_from_scenario(.x, .y)) %>%
mutate(
sample = factor(sample, levels = c("in","out")),
model = factor(model, levels = c("PLS","LM")),
metric = factor(metric, levels = c("RMSE","MAE"))
)
}
# --------- função principal ---------
predict_panel_table <- function(s_predict_obj,
digits = 3,
caption_prefix = "Predictive errors ",
scenario_order = c("MAIN","A","B")) {
df <- tidy_from_root(s_predict_obj)
# se algum cenário não estiver na lista, mantém no fim na ordem em que aparece
scenario_levels <- unique(c(scenario_order, setdiff(unique(df$scenario), scenario_order)))
df$scenario <- factor(df$scenario, levels = scenario_levels)
wide <- df %>%
group_by(scenario, indicator, sample, model, metric) %>%
summarise(value = mean(value), .groups = "drop") %>%
unite(col = key, sample, metric, model, sep = "_") %>%
pivot_wider(names_from = key, values_from = value)
need <- c("in_RMSE_PLS","in_RMSE_LM","in_MAE_PLS","in_MAE_LM",
"out_RMSE_PLS","out_RMSE_LM","out_MAE_PLS","out_MAE_LM")
for (cc in need) if (!cc %in% names(wide)) wide[[cc]] <- NA_real_
ratio <- function(num, den) ifelse(is.finite(num) & is.finite(den), num/den, NA_real_)
fmt <- function(x) ifelse(is.na(x), "", sprintf(paste0("%.", digits, "f"), x))
out_df <- wide %>%
arrange(scenario, indicator) %>%
mutate(
in_RMSE_R = ratio(in_RMSE_PLS, in_RMSE_LM),
in_MAE_R = ratio(in_MAE_PLS, in_MAE_LM),
out_RMSE_R = ratio(out_RMSE_PLS, out_RMSE_LM),
out_MAE_R = ratio(out_MAE_PLS, out_MAE_LM)
) %>%
transmute(
scenario, indicator,
in_RMSE_PLS = fmt(in_RMSE_PLS),
in_RMSE_LM = fmt(in_RMSE_LM),
in_RMSE_R = fmt(in_RMSE_R),
in_MAE_PLS = fmt(in_MAE_PLS),
in_MAE_LM = fmt(in_MAE_LM),
in_MAE_R = fmt(in_MAE_R),
out_RMSE_PLS = fmt(out_RMSE_PLS),
out_RMSE_LM = fmt(out_RMSE_LM),
out_RMSE_R = fmt(out_RMSE_R),
out_MAE_PLS = fmt(out_MAE_PLS),
out_MAE_LM = fmt(out_MAE_LM),
out_MAE_R = fmt(out_MAE_R)
)
# índices de agrupamento (antes de remover 'scenario')
idx <- out_df %>%
mutate(row_id = row_number()) %>%
group_by(scenario) %>%
summarise(start = min(row_id), end = max(row_id), .groups = "drop")
kb <- out_df %>%
select(-scenario) %>%
rename(Indicator = indicator) %>%
kable(
format = "html",
escape = FALSE,
align = c("l", rep("r", 12)),
col.names = c(
"Indicator",
"PLS","LM","PLS/LM","PLS","LM","PLS/LM",
"PLS","LM","PLS/LM","PLS","LM","PLS/LM"
),
caption = paste0(
"<b><span style='color:black'>", caption_prefix,
"<span></b><br> In-sample and out-of-sample; PLS/LM columns represent ratios."
)
) %>%
kable_styling(
bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE, position = "center", fixed_thead = TRUE
) %>%
add_header_above(c(" " = 1, "RMSE" = 3, "MAE" = 3, "RMSE" = 3, "MAE" = 3)) %>%
add_header_above(c(" " = 1, "in-sample" = 6, "out-sample" = 6))
# agrupa por cenário com NOME EM NEGRITO
if (nrow(idx) > 0) {
for (i in seq_len(nrow(idx))) {
kb <- kb %>%
group_rows(idx$scenario[i], idx$start[i], idx$end[i], bold = TRUE, italic = FALSE)
}
}
kb
}
# Refined
predict_panel_table(
s_predict_refined,
caption_prefix = "Predictive errors (RMSE/MAE) - Refined Model"
)
| Indicator | PLS | LM | PLS/LM | PLS | LM | PLS/LM | PLS | LM | PLS/LM | PLS | LM | PLS/LM |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Main sample | ||||||||||||
| clima | 0.994 | 0.879 | 1.131 | 0.623 | 0.505 | 1.235 | 0.995 | 0.885 | 1.124 | 0.624 | 0.508 | 1.227 |
| ecosy_1 | 0.929 | 0.649 | 1.430 | 0.665 | 0.408 | 1.629 | 0.930 | 0.654 | 1.422 | 0.666 | 0.411 | 1.621 |
| ecosy_2 | 0.926 | 0.644 | 1.437 | 0.683 | 0.419 | 1.629 | 0.927 | 0.648 | 1.429 | 0.684 | 0.422 | 1.620 |
| ecosy_3 | 0.998 | 0.935 | 1.067 | 0.765 | 0.713 | 1.072 | 0.999 | 0.942 | 1.060 | 0.765 | 0.718 | 1.066 |
| farmi_1 | 0.689 | 0.619 | 1.113 | 0.479 | 0.390 | 1.228 | 0.689 | 0.623 | 1.107 | 0.480 | 0.392 | 1.223 |
| farmi_2 | 0.901 | 0.802 | 1.123 | 0.736 | 0.636 | 1.157 | 0.902 | 0.806 | 1.118 | 0.737 | 0.639 | 1.152 |
| farmi_3 | 0.972 | 0.900 | 1.079 | 0.817 | 0.740 | 1.104 | 0.972 | 0.905 | 1.074 | 0.818 | 0.744 | 1.099 |
| farmi_4 | 0.944 | 0.897 | 1.053 | 0.779 | 0.726 | 1.072 | 0.945 | 0.900 | 1.049 | 0.779 | 0.729 | 1.068 |
| farmi_5 | 0.939 | 0.860 | 1.092 | 0.729 | 0.665 | 1.095 | 0.939 | 0.864 | 1.087 | 0.729 | 0.669 | 1.090 |
| farmi_6 | 0.969 | 0.838 | 1.157 | 0.787 | 0.668 | 1.179 | 0.970 | 0.844 | 1.149 | 0.788 | 0.671 | 1.173 |
| farmi_7 | 0.897 | 0.732 | 1.225 | 0.734 | 0.588 | 1.248 | 0.897 | 0.735 | 1.221 | 0.735 | 0.591 | 1.244 |
| farmi_8 | 0.980 | 0.942 | 1.041 | 0.678 | 0.643 | 1.054 | 0.981 | 0.947 | 1.036 | 0.678 | 0.646 | 1.050 |
| farmi_9 | 0.954 | 0.886 | 1.078 | 0.732 | 0.674 | 1.087 | 0.955 | 0.891 | 1.072 | 0.733 | 0.677 | 1.082 |
| foodenv_1 | 0.797 | 0.666 | 1.197 | 0.636 | 0.518 | 1.227 | 0.798 | 0.670 | 1.192 | 0.637 | 0.521 | 1.222 |
| foodenv_2 | 0.996 | 0.937 | 1.064 | 0.812 | 0.757 | 1.073 | 0.997 | 0.941 | 1.059 | 0.813 | 0.761 | 1.068 |
| foodenv_3 | 1.001 | 0.943 | 1.061 | 0.759 | 0.701 | 1.083 | 1.001 | 0.949 | 1.055 | 0.759 | 0.705 | 1.078 |
| foodenv_4 | 0.923 | 0.854 | 1.081 | 0.752 | 0.683 | 1.100 | 0.924 | 0.859 | 1.075 | 0.752 | 0.687 | 1.095 |
| foodsec | 0.611 | 0.539 | 1.134 | 0.465 | 0.410 | 1.133 | 0.612 | 0.543 | 1.128 | 0.466 | 0.413 | 1.128 |
| infra_1 | 0.996 | 0.766 | 1.302 | 0.770 | 0.592 | 1.300 | 0.997 | 0.771 | 1.293 | 0.770 | 0.596 | 1.292 |
| infra_2 | 0.997 | 0.893 | 1.117 | 0.754 | 0.674 | 1.118 | 0.997 | 0.898 | 1.110 | 0.754 | 0.677 | 1.113 |
| infra_3 | 0.995 | 0.833 | 1.195 | 0.813 | 0.658 | 1.234 | 0.995 | 0.838 | 1.188 | 0.813 | 0.662 | 1.227 |
| infra_4 | 0.992 | 0.799 | 1.242 | 0.766 | 0.580 | 1.322 | 0.993 | 0.803 | 1.235 | 0.766 | 0.583 | 1.315 |
| infra_5 | 0.994 | 0.927 | 1.072 | 0.734 | 0.695 | 1.056 | 0.994 | 0.932 | 1.067 | 0.734 | 0.699 | 1.050 |
| nutri_1 | 0.959 | 0.895 | 1.071 | 0.760 | 0.704 | 1.080 | 0.959 | 0.901 | 1.065 | 0.760 | 0.708 | 1.074 |
| nutri_2 | 0.987 | 0.965 | 1.023 | 0.810 | 0.789 | 1.027 | 0.987 | 0.970 | 1.017 | 0.811 | 0.793 | 1.022 |
| nutri_4 | 0.913 | 0.853 | 1.071 | 0.713 | 0.654 | 1.089 | 0.914 | 0.857 | 1.066 | 0.713 | 0.658 | 1.084 |
| Scenario A | ||||||||||||
| clima | 0.993 | 0.885 | 1.122 | 0.623 | 0.510 | 1.222 | 0.994 | 0.891 | 1.115 | 0.623 | 0.513 | 1.215 |
| ecosy_1 | 0.929 | 0.655 | 1.418 | 0.665 | 0.403 | 1.649 | 0.929 | 0.660 | 1.409 | 0.665 | 0.405 | 1.641 |
| ecosy_2 | 0.926 | 0.642 | 1.442 | 0.683 | 0.413 | 1.651 | 0.926 | 0.646 | 1.434 | 0.683 | 0.416 | 1.642 |
| ecosy_3 | 0.998 | 0.935 | 1.067 | 0.765 | 0.713 | 1.072 | 0.999 | 0.942 | 1.060 | 0.765 | 0.717 | 1.067 |
| farmi_1 | 0.588 | 0.530 | 1.109 | 0.441 | 0.364 | 1.211 | 0.589 | 0.533 | 1.104 | 0.441 | 0.366 | 1.206 |
| farmi_2 | 0.901 | 0.805 | 1.119 | 0.736 | 0.639 | 1.153 | 0.902 | 0.809 | 1.115 | 0.737 | 0.641 | 1.149 |
| farmi_3 | 0.972 | 0.903 | 1.076 | 0.817 | 0.743 | 1.099 | 0.972 | 0.907 | 1.072 | 0.818 | 0.746 | 1.096 |
| farmi_4 | 0.945 | 0.897 | 1.053 | 0.779 | 0.727 | 1.072 | 0.945 | 0.901 | 1.049 | 0.780 | 0.730 | 1.068 |
| farmi_5 | 0.939 | 0.860 | 1.091 | 0.729 | 0.666 | 1.095 | 0.940 | 0.865 | 1.087 | 0.729 | 0.669 | 1.091 |
| farmi_6 | 0.968 | 0.838 | 1.155 | 0.787 | 0.669 | 1.176 | 0.969 | 0.844 | 1.148 | 0.787 | 0.673 | 1.170 |
| farmi_7 | 0.898 | 0.732 | 1.227 | 0.736 | 0.588 | 1.251 | 0.899 | 0.736 | 1.222 | 0.736 | 0.591 | 1.245 |
| farmi_8 | 0.980 | 0.943 | 1.039 | 0.678 | 0.644 | 1.053 | 0.981 | 0.948 | 1.034 | 0.678 | 0.647 | 1.048 |
| farmi_9 | 0.955 | 0.886 | 1.078 | 0.733 | 0.674 | 1.088 | 0.956 | 0.890 | 1.074 | 0.733 | 0.677 | 1.084 |
| foodenv_1 | 0.793 | 0.666 | 1.191 | 0.632 | 0.518 | 1.220 | 0.795 | 0.670 | 1.185 | 0.634 | 0.522 | 1.215 |
| foodenv_2 | 0.996 | 0.936 | 1.064 | 0.812 | 0.757 | 1.073 | 0.996 | 0.941 | 1.059 | 0.813 | 0.761 | 1.068 |
| foodenv_3 | 0.739 | 0.713 | 1.037 | 0.665 | 0.626 | 1.062 | 0.739 | 0.717 | 1.031 | 0.665 | 0.630 | 1.056 |
| foodenv_4 | 0.923 | 0.854 | 1.081 | 0.752 | 0.683 | 1.101 | 0.924 | 0.859 | 1.075 | 0.753 | 0.687 | 1.095 |
| foodsec | 0.610 | 0.538 | 1.133 | 0.465 | 0.410 | 1.134 | 0.611 | 0.542 | 1.126 | 0.465 | 0.413 | 1.127 |
| infra_1 | 0.996 | 0.766 | 1.301 | 0.770 | 0.593 | 1.299 | 0.997 | 0.771 | 1.294 | 0.770 | 0.596 | 1.293 |
| infra_2 | 0.997 | 0.892 | 1.117 | 0.754 | 0.674 | 1.119 | 0.997 | 0.898 | 1.110 | 0.754 | 0.677 | 1.113 |
| infra_3 | 0.995 | 0.832 | 1.195 | 0.812 | 0.658 | 1.235 | 0.995 | 0.838 | 1.188 | 0.813 | 0.662 | 1.228 |
| infra_4 | 0.992 | 0.800 | 1.241 | 0.766 | 0.580 | 1.320 | 0.993 | 0.805 | 1.234 | 0.766 | 0.584 | 1.313 |
| infra_5 | 0.994 | 0.927 | 1.073 | 0.734 | 0.695 | 1.056 | 0.995 | 0.932 | 1.067 | 0.734 | 0.699 | 1.051 |
| nutri_1 | 0.959 | 0.895 | 1.071 | 0.760 | 0.704 | 1.080 | 0.959 | 0.900 | 1.066 | 0.760 | 0.707 | 1.075 |
| nutri_2 | 0.987 | 0.965 | 1.022 | 0.811 | 0.790 | 1.026 | 0.987 | 0.970 | 1.018 | 0.811 | 0.794 | 1.021 |
| nutri_4 | 0.914 | 0.853 | 1.072 | 0.713 | 0.655 | 1.090 | 0.914 | 0.857 | 1.067 | 0.714 | 0.658 | 1.085 |
| Scenario B | ||||||||||||
| clima | 0.978 | 0.875 | 1.118 | 0.611 | 0.506 | 1.207 | 0.980 | 0.881 | 1.112 | 0.612 | 0.510 | 1.201 |
| ecosy_1 | 0.810 | 0.573 | 1.414 | 0.597 | 0.356 | 1.676 | 0.812 | 0.577 | 1.406 | 0.598 | 0.359 | 1.666 |
| ecosy_2 | 0.827 | 0.575 | 1.439 | 0.623 | 0.374 | 1.668 | 0.828 | 0.578 | 1.433 | 0.624 | 0.376 | 1.660 |
| ecosy_3 | 1.017 | 0.950 | 1.070 | 0.782 | 0.727 | 1.075 | 1.018 | 0.957 | 1.063 | 0.782 | 0.733 | 1.068 |
| farmi_1 | 0.507 | 0.463 | 1.097 | 0.378 | 0.318 | 1.189 | 0.508 | 0.465 | 1.092 | 0.378 | 0.320 | 1.184 |
| farmi_2 | 0.912 | 0.811 | 1.124 | 0.747 | 0.647 | 1.155 | 0.913 | 0.816 | 1.120 | 0.748 | 0.651 | 1.150 |
| farmi_3 | 0.980 | 0.907 | 1.081 | 0.824 | 0.748 | 1.102 | 0.981 | 0.912 | 1.076 | 0.824 | 0.751 | 1.098 |
| farmi_4 | 0.945 | 0.900 | 1.050 | 0.779 | 0.730 | 1.066 | 0.945 | 0.904 | 1.045 | 0.779 | 0.734 | 1.062 |
| farmi_5 | 0.943 | 0.863 | 1.093 | 0.731 | 0.667 | 1.096 | 0.943 | 0.867 | 1.088 | 0.732 | 0.671 | 1.091 |
| farmi_6 | 0.953 | 0.833 | 1.144 | 0.772 | 0.663 | 1.165 | 0.953 | 0.839 | 1.136 | 0.773 | 0.667 | 1.159 |
| farmi_7 | 0.891 | 0.732 | 1.217 | 0.728 | 0.589 | 1.235 | 0.892 | 0.736 | 1.211 | 0.728 | 0.593 | 1.228 |
| farmi_8 | 0.957 | 0.931 | 1.028 | 0.657 | 0.631 | 1.042 | 0.958 | 0.937 | 1.022 | 0.657 | 0.634 | 1.036 |
| farmi_9 | 0.950 | 0.879 | 1.080 | 0.727 | 0.667 | 1.090 | 0.950 | 0.883 | 1.076 | 0.728 | 0.670 | 1.087 |
| foodenv_1 | 0.779 | 0.664 | 1.174 | 0.622 | 0.520 | 1.196 | 0.781 | 0.669 | 1.167 | 0.623 | 0.523 | 1.190 |
| foodenv_2 | 1.011 | 0.950 | 1.064 | 0.827 | 0.770 | 1.074 | 1.011 | 0.956 | 1.058 | 0.828 | 0.775 | 1.068 |
| foodenv_3 | 0.592 | 0.582 | 1.017 | 0.524 | 0.507 | 1.033 | 0.592 | 0.585 | 1.012 | 0.524 | 0.510 | 1.028 |
| foodenv_4 | 0.916 | 0.851 | 1.076 | 0.741 | 0.677 | 1.094 | 0.917 | 0.857 | 1.071 | 0.741 | 0.682 | 1.088 |
| foodsec | 0.613 | 0.544 | 1.126 | 0.466 | 0.414 | 1.126 | 0.613 | 0.548 | 1.119 | 0.467 | 0.417 | 1.120 |
| infra_1 | 0.946 | 0.756 | 1.252 | 0.732 | 0.585 | 1.253 | 0.947 | 0.761 | 1.244 | 0.732 | 0.588 | 1.245 |
| infra_2 | 1.017 | 0.912 | 1.116 | 0.771 | 0.691 | 1.115 | 1.018 | 0.918 | 1.110 | 0.771 | 0.695 | 1.109 |
| infra_3 | 1.000 | 0.851 | 1.175 | 0.816 | 0.674 | 1.211 | 1.001 | 0.857 | 1.168 | 0.817 | 0.678 | 1.204 |
| infra_4 | 0.983 | 0.804 | 1.223 | 0.757 | 0.586 | 1.293 | 0.984 | 0.809 | 1.216 | 0.758 | 0.589 | 1.286 |
| infra_5 | 0.864 | 0.813 | 1.063 | 0.645 | 0.618 | 1.044 | 0.864 | 0.818 | 1.057 | 0.646 | 0.622 | 1.039 |
| nutri_1 | 0.954 | 0.895 | 1.065 | 0.754 | 0.702 | 1.075 | 0.955 | 0.903 | 1.058 | 0.755 | 0.707 | 1.068 |
| nutri_2 | 0.988 | 0.966 | 1.023 | 0.812 | 0.790 | 1.028 | 0.989 | 0.972 | 1.017 | 0.812 | 0.795 | 1.022 |
| nutri_4 | 0.909 | 0.853 | 1.066 | 0.706 | 0.653 | 1.082 | 0.910 | 0.859 | 1.059 | 0.707 | 0.658 | 1.075 |
# Full
predict_panel_table(
s_predict_full,
caption_prefix = "Predictive errors (RMSE/MAE) - Full Model"
)
| Indicator | PLS | LM | PLS/LM | PLS | LM | PLS/LM | PLS | LM | PLS/LM | PLS | LM | PLS/LM |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Main sample | ||||||||||||
| clima | 0.994 | 0.878 | 1.132 | 0.623 | 0.504 | 1.237 | 0.995 | 0.885 | 1.124 | 0.623 | 0.508 | 1.228 |
| ecosy_1 | 0.929 | 0.649 | 1.431 | 0.665 | 0.408 | 1.629 | 0.929 | 0.654 | 1.420 | 0.665 | 0.411 | 1.618 |
| ecosy_2 | 0.926 | 0.643 | 1.439 | 0.683 | 0.419 | 1.629 | 0.926 | 0.648 | 1.430 | 0.683 | 0.422 | 1.619 |
| ecosy_3 | 0.998 | 0.935 | 1.068 | 0.765 | 0.713 | 1.073 | 0.999 | 0.941 | 1.061 | 0.765 | 0.718 | 1.066 |
| farmi_1 | 0.691 | 0.619 | 1.117 | 0.482 | 0.390 | 1.234 | 0.692 | 0.624 | 1.109 | 0.482 | 0.393 | 1.227 |
| farmi_2 | 0.901 | 0.802 | 1.123 | 0.736 | 0.636 | 1.157 | 0.902 | 0.806 | 1.118 | 0.736 | 0.639 | 1.153 |
| farmi_3 | 0.972 | 0.900 | 1.080 | 0.817 | 0.740 | 1.104 | 0.972 | 0.905 | 1.074 | 0.818 | 0.744 | 1.099 |
| farmi_4 | 0.944 | 0.897 | 1.053 | 0.779 | 0.726 | 1.073 | 0.945 | 0.901 | 1.049 | 0.780 | 0.730 | 1.068 |
| farmi_5 | 0.939 | 0.860 | 1.092 | 0.728 | 0.665 | 1.095 | 0.939 | 0.864 | 1.087 | 0.729 | 0.668 | 1.091 |
| farmi_6 | 0.969 | 0.834 | 1.162 | 0.787 | 0.662 | 1.188 | 0.969 | 0.838 | 1.156 | 0.787 | 0.665 | 1.183 |
| farmi_7 | 0.896 | 0.731 | 1.226 | 0.734 | 0.588 | 1.249 | 0.897 | 0.734 | 1.221 | 0.735 | 0.590 | 1.244 |
| farmi_8 | 0.980 | 0.941 | 1.041 | 0.678 | 0.643 | 1.054 | 0.981 | 0.947 | 1.035 | 0.679 | 0.647 | 1.049 |
| farmi_9 | 0.954 | 0.884 | 1.080 | 0.732 | 0.671 | 1.091 | 0.955 | 0.888 | 1.075 | 0.733 | 0.674 | 1.086 |
| foodenv_1 | 0.796 | 0.665 | 1.196 | 0.635 | 0.518 | 1.227 | 0.797 | 0.670 | 1.190 | 0.636 | 0.521 | 1.221 |
| foodenv_2 | 0.997 | 0.933 | 1.069 | 0.813 | 0.754 | 1.077 | 0.998 | 0.939 | 1.063 | 0.813 | 0.759 | 1.071 |
| foodenv_3 | 1.000 | 0.942 | 1.061 | 0.759 | 0.701 | 1.083 | 1.001 | 0.948 | 1.055 | 0.759 | 0.705 | 1.077 |
| foodenv_4 | 0.922 | 0.854 | 1.081 | 0.751 | 0.682 | 1.101 | 0.923 | 0.858 | 1.076 | 0.752 | 0.686 | 1.096 |
| foodsec | 0.611 | 0.519 | 1.176 | 0.465 | 0.395 | 1.177 | 0.612 | 0.523 | 1.169 | 0.466 | 0.398 | 1.171 |
| infra_1 | 0.996 | 0.765 | 1.302 | 0.770 | 0.591 | 1.302 | 0.997 | 0.770 | 1.295 | 0.770 | 0.594 | 1.295 |
| infra_2 | 0.997 | 0.891 | 1.119 | 0.754 | 0.672 | 1.121 | 0.997 | 0.897 | 1.112 | 0.754 | 0.676 | 1.114 |
| infra_3 | 0.995 | 0.832 | 1.195 | 0.813 | 0.658 | 1.235 | 0.995 | 0.837 | 1.189 | 0.813 | 0.661 | 1.229 |
| infra_4 | 0.992 | 0.799 | 1.242 | 0.766 | 0.580 | 1.322 | 0.993 | 0.804 | 1.234 | 0.767 | 0.583 | 1.315 |
| infra_5 | 0.994 | 0.927 | 1.072 | 0.734 | 0.695 | 1.056 | 0.995 | 0.932 | 1.067 | 0.734 | 0.699 | 1.050 |
| nutri_1 | 0.958 | 0.895 | 1.071 | 0.759 | 0.703 | 1.079 | 0.959 | 0.901 | 1.064 | 0.760 | 0.708 | 1.073 |
| nutri_2 | 0.987 | 0.965 | 1.023 | 0.811 | 0.789 | 1.027 | 0.988 | 0.970 | 1.018 | 0.811 | 0.794 | 1.022 |
| nutri_3 | 0.914 | 0.860 | 1.062 | 0.699 | 0.650 | 1.077 | 0.914 | 0.865 | 1.057 | 0.700 | 0.653 | 1.071 |
| nutri_4 | 0.914 | 0.852 | 1.072 | 0.713 | 0.654 | 1.090 | 0.914 | 0.858 | 1.065 | 0.714 | 0.659 | 1.083 |
| nutri_5 | 0.925 | 0.879 | 1.052 | 0.726 | 0.685 | 1.060 | 0.926 | 0.884 | 1.048 | 0.726 | 0.688 | 1.055 |
| Scenario A | ||||||||||||
| clima | 0.993 | 0.884 | 1.123 | 0.623 | 0.509 | 1.223 | 0.994 | 0.891 | 1.115 | 0.623 | 0.513 | 1.215 |
| ecosy_1 | 0.929 | 0.655 | 1.418 | 0.665 | 0.403 | 1.649 | 0.930 | 0.659 | 1.411 | 0.666 | 0.406 | 1.640 |
| ecosy_2 | 0.926 | 0.640 | 1.445 | 0.683 | 0.414 | 1.650 | 0.927 | 0.644 | 1.438 | 0.684 | 0.416 | 1.643 |
| ecosy_3 | 0.998 | 0.935 | 1.068 | 0.765 | 0.713 | 1.073 | 0.999 | 0.941 | 1.061 | 0.765 | 0.717 | 1.066 |
| farmi_1 | 0.590 | 0.530 | 1.113 | 0.443 | 0.364 | 1.218 | 0.591 | 0.533 | 1.108 | 0.443 | 0.366 | 1.213 |
| farmi_2 | 0.901 | 0.805 | 1.120 | 0.736 | 0.638 | 1.153 | 0.902 | 0.809 | 1.115 | 0.737 | 0.641 | 1.149 |
| farmi_3 | 0.972 | 0.903 | 1.076 | 0.817 | 0.743 | 1.100 | 0.972 | 0.908 | 1.071 | 0.817 | 0.747 | 1.095 |
| farmi_4 | 0.945 | 0.897 | 1.053 | 0.780 | 0.727 | 1.073 | 0.945 | 0.902 | 1.048 | 0.780 | 0.731 | 1.067 |
| farmi_5 | 0.939 | 0.860 | 1.091 | 0.729 | 0.666 | 1.095 | 0.939 | 0.864 | 1.088 | 0.729 | 0.668 | 1.091 |
| farmi_6 | 0.969 | 0.834 | 1.161 | 0.786 | 0.663 | 1.186 | 0.969 | 0.841 | 1.152 | 0.787 | 0.667 | 1.179 |
| farmi_7 | 0.898 | 0.732 | 1.228 | 0.736 | 0.588 | 1.251 | 0.899 | 0.736 | 1.221 | 0.736 | 0.591 | 1.245 |
| farmi_8 | 0.980 | 0.943 | 1.040 | 0.678 | 0.644 | 1.053 | 0.980 | 0.948 | 1.034 | 0.678 | 0.648 | 1.047 |
| farmi_9 | 0.955 | 0.884 | 1.080 | 0.733 | 0.671 | 1.092 | 0.956 | 0.889 | 1.075 | 0.733 | 0.675 | 1.087 |
| foodenv_1 | 0.792 | 0.666 | 1.190 | 0.632 | 0.518 | 1.220 | 0.794 | 0.671 | 1.184 | 0.633 | 0.522 | 1.213 |
| foodenv_2 | 0.997 | 0.933 | 1.069 | 0.813 | 0.754 | 1.077 | 0.998 | 0.939 | 1.062 | 0.813 | 0.759 | 1.071 |
| foodenv_3 | 0.739 | 0.712 | 1.037 | 0.665 | 0.626 | 1.062 | 0.739 | 0.716 | 1.031 | 0.665 | 0.629 | 1.057 |
| foodenv_4 | 0.923 | 0.854 | 1.081 | 0.752 | 0.682 | 1.102 | 0.923 | 0.859 | 1.075 | 0.752 | 0.686 | 1.096 |
| foodsec | 0.610 | 0.519 | 1.175 | 0.464 | 0.395 | 1.177 | 0.610 | 0.523 | 1.167 | 0.465 | 0.398 | 1.169 |
| infra_1 | 0.996 | 0.766 | 1.302 | 0.770 | 0.592 | 1.301 | 0.997 | 0.770 | 1.294 | 0.770 | 0.595 | 1.294 |
| infra_2 | 0.997 | 0.891 | 1.120 | 0.754 | 0.672 | 1.121 | 0.997 | 0.897 | 1.112 | 0.754 | 0.677 | 1.114 |
| infra_3 | 0.995 | 0.832 | 1.196 | 0.812 | 0.658 | 1.235 | 0.995 | 0.837 | 1.189 | 0.813 | 0.661 | 1.229 |
| infra_4 | 0.992 | 0.800 | 1.241 | 0.766 | 0.580 | 1.320 | 0.993 | 0.805 | 1.234 | 0.766 | 0.584 | 1.313 |
| infra_5 | 0.994 | 0.927 | 1.073 | 0.734 | 0.695 | 1.056 | 0.994 | 0.932 | 1.066 | 0.734 | 0.699 | 1.050 |
| nutri_1 | 0.958 | 0.895 | 1.070 | 0.759 | 0.704 | 1.079 | 0.959 | 0.901 | 1.064 | 0.760 | 0.708 | 1.074 |
| nutri_2 | 0.987 | 0.965 | 1.023 | 0.811 | 0.790 | 1.026 | 0.988 | 0.970 | 1.018 | 0.811 | 0.794 | 1.022 |
| nutri_3 | 0.914 | 0.861 | 1.062 | 0.700 | 0.650 | 1.077 | 0.915 | 0.865 | 1.057 | 0.701 | 0.653 | 1.072 |
| nutri_4 | 0.914 | 0.853 | 1.072 | 0.714 | 0.655 | 1.090 | 0.915 | 0.858 | 1.067 | 0.714 | 0.658 | 1.085 |
| nutri_5 | 0.925 | 0.880 | 1.052 | 0.726 | 0.685 | 1.060 | 0.926 | 0.884 | 1.047 | 0.727 | 0.689 | 1.055 |
| Scenario B | ||||||||||||
| clima | 0.978 | 0.874 | 1.119 | 0.611 | 0.505 | 1.209 | 0.980 | 0.881 | 1.112 | 0.612 | 0.509 | 1.202 |
| ecosy_1 | 0.810 | 0.572 | 1.416 | 0.597 | 0.357 | 1.673 | 0.811 | 0.577 | 1.406 | 0.598 | 0.359 | 1.662 |
| ecosy_2 | 0.827 | 0.574 | 1.441 | 0.623 | 0.374 | 1.669 | 0.828 | 0.579 | 1.431 | 0.624 | 0.376 | 1.660 |
| ecosy_3 | 1.017 | 0.950 | 1.071 | 0.782 | 0.727 | 1.075 | 1.017 | 0.957 | 1.063 | 0.782 | 0.732 | 1.068 |
| farmi_1 | 0.509 | 0.462 | 1.100 | 0.380 | 0.318 | 1.195 | 0.510 | 0.466 | 1.095 | 0.380 | 0.320 | 1.189 |
| farmi_2 | 0.912 | 0.811 | 1.125 | 0.747 | 0.647 | 1.155 | 0.913 | 0.816 | 1.119 | 0.748 | 0.651 | 1.149 |
| farmi_3 | 0.980 | 0.907 | 1.081 | 0.824 | 0.747 | 1.102 | 0.981 | 0.912 | 1.075 | 0.824 | 0.752 | 1.097 |
| farmi_4 | 0.945 | 0.900 | 1.050 | 0.779 | 0.730 | 1.066 | 0.945 | 0.905 | 1.045 | 0.779 | 0.734 | 1.061 |
| farmi_5 | 0.942 | 0.862 | 1.093 | 0.731 | 0.667 | 1.096 | 0.943 | 0.868 | 1.087 | 0.732 | 0.671 | 1.090 |
| farmi_6 | 0.953 | 0.829 | 1.149 | 0.772 | 0.658 | 1.174 | 0.954 | 0.836 | 1.142 | 0.773 | 0.662 | 1.167 |
| farmi_7 | 0.890 | 0.732 | 1.217 | 0.727 | 0.589 | 1.235 | 0.891 | 0.736 | 1.210 | 0.728 | 0.593 | 1.228 |
| farmi_8 | 0.957 | 0.930 | 1.029 | 0.657 | 0.631 | 1.042 | 0.958 | 0.937 | 1.023 | 0.658 | 0.634 | 1.037 |
| farmi_9 | 0.950 | 0.878 | 1.082 | 0.727 | 0.665 | 1.093 | 0.950 | 0.882 | 1.077 | 0.727 | 0.668 | 1.088 |
| foodenv_1 | 0.779 | 0.663 | 1.174 | 0.621 | 0.519 | 1.196 | 0.780 | 0.669 | 1.167 | 0.622 | 0.523 | 1.190 |
| foodenv_2 | 1.011 | 0.946 | 1.069 | 0.827 | 0.767 | 1.079 | 1.012 | 0.954 | 1.062 | 0.828 | 0.773 | 1.072 |
| foodenv_3 | 0.592 | 0.582 | 1.017 | 0.524 | 0.507 | 1.033 | 0.592 | 0.585 | 1.011 | 0.524 | 0.510 | 1.028 |
| foodenv_4 | 0.916 | 0.851 | 1.076 | 0.740 | 0.677 | 1.094 | 0.916 | 0.857 | 1.070 | 0.741 | 0.681 | 1.087 |
| foodsec | 0.612 | 0.525 | 1.165 | 0.466 | 0.400 | 1.166 | 0.613 | 0.530 | 1.156 | 0.467 | 0.403 | 1.157 |
| infra_1 | 0.946 | 0.755 | 1.253 | 0.732 | 0.584 | 1.254 | 0.947 | 0.761 | 1.243 | 0.732 | 0.588 | 1.245 |
| infra_2 | 1.017 | 0.910 | 1.118 | 0.771 | 0.690 | 1.117 | 1.018 | 0.916 | 1.111 | 0.771 | 0.694 | 1.110 |
| infra_3 | 1.000 | 0.851 | 1.175 | 0.816 | 0.674 | 1.211 | 1.001 | 0.857 | 1.168 | 0.817 | 0.678 | 1.205 |
| infra_4 | 0.983 | 0.803 | 1.224 | 0.757 | 0.585 | 1.294 | 0.984 | 0.811 | 1.214 | 0.758 | 0.590 | 1.284 |
| infra_5 | 0.864 | 0.813 | 1.063 | 0.646 | 0.618 | 1.044 | 0.864 | 0.818 | 1.056 | 0.646 | 0.623 | 1.037 |
| nutri_1 | 0.953 | 0.895 | 1.064 | 0.753 | 0.702 | 1.073 | 0.954 | 0.902 | 1.058 | 0.754 | 0.706 | 1.068 |
| nutri_2 | 0.989 | 0.966 | 1.023 | 0.812 | 0.790 | 1.028 | 0.990 | 0.972 | 1.018 | 0.813 | 0.795 | 1.022 |
| nutri_3 | 0.910 | 0.859 | 1.059 | 0.694 | 0.647 | 1.073 | 0.910 | 0.865 | 1.052 | 0.694 | 0.652 | 1.066 |
| nutri_4 | 0.909 | 0.853 | 1.066 | 0.707 | 0.653 | 1.082 | 0.910 | 0.859 | 1.059 | 0.707 | 0.658 | 1.076 |
| nutri_5 | 0.916 | 0.873 | 1.050 | 0.717 | 0.677 | 1.059 | 0.917 | 0.878 | 1.045 | 0.718 | 0.682 | 1.053 |
Key Points (Structure Evaluation). The structural model shows strong internal consistency and theoretical alignment. Collinearity diagnostics confirmed confirmed no critical issues, with all VIF below 3. The main sustemic pathway (
INFRA -> ECOSY -> FARMI -> FOODENV -> FOODSEC), is robust and consistent across scenarios, with large and significant effects forINFRAandECOSYas upstream drivers, and FARMI and FOODENV as key transmission channels. Deviations concentrate inCLIMAand NUTRI, where small or negative coefficients (e.g.,FARMI -> CLIMA/NUTRI,FOODEV -> NUTRI) mirror mixed formative weights and indicate contextual trade-offs rather than model misspecification. Explanatory power is substantial forFARMIandFOODSEC(\(R^2\) approx. 0.60), moderate for FOODENV (approx. 0.40), and weak-to-moderate for ECOSY and NUTRI (approx. 0.15 to 0.26). Large \(f^2\) effects forECOSY -> FARMI,FARMI -> FOODENV, andFOODENV -> FOODSECconfirm the centrality of these links. Predictive assessment using PLSpredict shows that the linear benchmark (LM) generally achieves lower RMSE and MAE errors, while PLS-SEM reaches near-parity for a few indicators. Overall, the structure demonstrates coherent and stable relationshios across specifications, with the results consistent between the Refined and Full models and across robustness scenarios.
All analyses were performed in R, using the packages listed in the setup section of this document. The session information below allows full reproducibility of the computational environment.
sessionInfo()
## R version 4.5.1 (2025-06-13 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26100)
##
## Matrix products: default
## LAPACK version 3.12.1
##
## locale:
## [1] LC_COLLATE=Portuguese_Brazil.utf8 LC_CTYPE=Portuguese_Brazil.utf8
## [3] LC_MONETARY=Portuguese_Brazil.utf8 LC_NUMERIC=C
## [5] LC_TIME=Portuguese_Brazil.utf8
##
## time zone: America/Sao_Paulo
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] ggraph_2.2.2 tidygraph_1.3.1 DescTools_0.99.60 viridis_0.6.5
## [5] viridisLite_0.4.2 janitor_2.2.1 readxl_1.4.5 kableExtra_1.4.0
## [9] seminr_2.3.1 lubridate_1.9.4 forcats_1.0.0 stringr_1.5.1
## [13] dplyr_1.1.4 purrr_1.1.0 readr_2.1.5 tidyr_1.3.1
## [17] tibble_3.3.0 ggplot2_4.0.0 tidyverse_2.0.0
##
## loaded via a namespace (and not attached):
## [1] tidyselect_1.2.1 Exact_3.3 rootSolve_1.8.2.4 farver_2.1.2
## [5] S7_0.2.0 fastmap_1.2.0 tweenr_2.0.3 digest_0.6.37
## [9] timechange_0.3.0 lifecycle_1.0.4 lmom_3.2 magrittr_2.0.3
## [13] compiler_4.5.1 rlang_1.1.6 sass_0.4.10 tools_4.5.1
## [17] igraph_2.1.4 yaml_2.3.10 data.table_1.17.8 knitr_1.50
## [21] htmlwidgets_1.6.4 graphlayouts_1.2.2 xml2_1.4.0 RColorBrewer_1.1-3
## [25] expm_1.0-0 withr_3.0.2 grid_4.5.1 polyclip_1.10-7
## [29] e1071_1.7-16 scales_1.4.0 MASS_7.3-65 dichromat_2.0-0.1
## [33] cli_3.6.5 mvtnorm_1.3-3 DiagrammeR_1.0.11 rmarkdown_2.30
## [37] generics_0.1.4 rstudioapi_0.17.1 httr_1.4.7 tzdb_0.5.0
## [41] visNetwork_2.1.2 gld_2.6.7 cachem_1.1.0 ggforce_0.5.0
## [45] proxy_0.4-27 parallel_4.5.1 cellranger_1.1.0 vctrs_0.6.5
## [49] boot_1.3-31 Matrix_1.7-3 jsonlite_2.0.0 hms_1.1.3
## [53] ggrepel_0.9.6 systemfonts_1.2.3 jquerylib_0.1.4 glue_1.8.0
## [57] codetools_0.2-20 stringi_1.8.7 gtable_0.3.6 pillar_1.11.0
## [61] htmltools_0.5.8.1 R6_2.6.1 textshaping_1.0.1 evaluate_1.0.5
## [65] lattice_0.22-7 haven_2.5.5 memoise_2.0.1 snakecase_0.11.1
## [69] bslib_0.9.0 class_7.3-23 Rcpp_1.1.0 svglite_2.2.1
## [73] gridExtra_2.3 xfun_0.52 fs_1.6.6 pkgconfig_2.0.3
Hair, J. F., Black, W. C., Babin, B. J., & Anderson, R. E. (2019). Multivariate Data Analysis (8th ed.). Cengage.
Hair, J. F., Hult, G. T. M., Ringle, C. M., Sarstedt, M., Danks, N. P., & Ray, S. (2021). PLS-SEM Using R: A Workbook. Springer.