# install.packages("seminr")
library(seminr)
# install.packages("readxl") # run once
library(readxl)
my_data <- read_excel(path = "WL_TPB_Poland_Survey_2025.xlsx", sheet = 3)
my_data
head(my_data)
colnames(my_data)
## [1] "ID" "Time"
## [3] "Age_group" "Residence"
## [5] "Med_city_size" "large_city_size"
## [7] "Province" "Climate_change_belief"
## [9] "Wft" "ATT1"
## [11] "ATT2" "ATT3"
## [13] "SN1" "SN2"
## [15] "SN3" "PBC1"
## [17] "PBC2" "PBC3"
## [19] "PI1" "PI2"
## [21] "PI3" "WL1"
## [23] "WL2" "WL3"
## [25] "WL4" "Education"
## [27] "Food_choice_willingness"
# to create reflective mm (no need to write mode_A)
simple_mm<- constructs(
composite("PI", multi_items("PI",1:3)),
composite("ATT", multi_items("ATT",1:3)),
composite("SN", multi_items("SN",1:3)),
composite("PBC", multi_items("PBC",2:3)), #PBC1 was removed because loading=0.540 and alpha< 0.7its removal has a better effect on reliability and validity metrics/content validity (<0.708 recommendation limit)
composite("WL", multi_items("WL",1:4))
)
simple_mm
## $composite
## [1] "PI" "PI1" "A" "PI" "PI2" "A" "PI" "PI3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "ATT" "ATT1" "A" "ATT" "ATT2" "A" "ATT" "ATT3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "SN" "SN1" "A" "SN" "SN2" "A" "SN" "SN3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "PBC" "PBC2" "A" "PBC" "PBC3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "WL" "WL1" "A" "WL" "WL2" "A" "WL" "WL3" "A" "WL" "WL4" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## attr(,"class")
## [1] "list" "measurement_model" "seminr_model"
# to create sm
simple_sm <- relationships(
paths(from = c("ATT","SN","PBC","WL"), to = "PI")
)
simple_sm
## source target
## [1,] "ATT" "PI"
## [2,] "SN" "PI"
## [3,] "PBC" "PI"
## [4,] "WL" "PI"
## attr(,"class")
## [1] "matrix" "array" "structural_model" "seminr_model"
# to estimate the model
simple_model <- estimate_pls(data = my_data,
measurement_model = simple_mm,
structural_model = simple_sm,
inner_weights = path_weighting,
missing = mean_replacement,
missing_value = "-99")
## Generating the seminr model
## All 999 observations are valid.
# summary() [gives info about sub-meta]can be used for estimate_pls(), bootstrap_model() and predict_pls() functions
summary_simple <- summary(simple_model) #shows the path coefficients and reliability
summary_simple
##
## Results from package seminr (2.3.7)
##
## Path Coefficients:
## PI
## R^2 0.718
## AdjR^2 0.717
## ATT 0.182
## SN 0.152
## PBC 0.157
## WL 0.493
##
## Reliability:
## alpha rhoC AVE rhoA
## ATT 0.924 0.952 0.869 0.927
## SN 0.925 0.952 0.870 0.926
## PBC 0.744 0.886 0.796 0.744
## WL 0.850 0.898 0.689 0.879
## PI 0.950 0.968 0.909 0.950
##
## Alpha, rhoC, and rhoA should exceed 0.7 while AVE should exceed 0.5
# plot the see estimated model
plot(simple_model) #β IS PATH COEFFICIENT ; λ IS outer loadings
summary_simple$iterations # should be lower than 300
## [1] 3
boot_simple <- bootstrap_model(
seminr_model = simple_model,
nboot = 10000,
cores = NULL,
seed = 123
)
## Bootstrapping model using seminr...
## SEMinR Model successfully bootstrapped
# store the summary of the bootstrapped model
# A path is significant when its **t-value exceeds 1.96 and its 95% confidence interval does not include zero
summary_boot <- summary(boot_simple,alpha=0.10)
summary_boot
##
## Results from Bootstrap resamples: 10000
##
## Bootstrapped Structural Paths:
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 5% CI 95% CI
## ATT -> PI 0.182 0.183 0.028 6.409 0.136 0.230
## SN -> PI 0.152 0.152 0.032 4.764 0.099 0.204
## PBC -> PI 0.157 0.156 0.033 4.787 0.103 0.210
## WL -> PI 0.493 0.493 0.033 14.719 0.437 0.547
##
## Bootstrapped Weights:
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 5% CI 95% CI
## PI1 -> PI 0.346 0.346 0.003 137.451 0.342 0.350
## PI2 -> PI 0.352 0.352 0.003 137.163 0.348 0.356
## PI3 -> PI 0.351 0.351 0.003 108.499 0.346 0.357
## ATT1 -> ATT 0.369 0.369 0.007 55.755 0.358 0.380
## ATT2 -> ATT 0.365 0.365 0.007 49.609 0.353 0.377
## ATT3 -> ATT 0.339 0.339 0.007 46.059 0.327 0.351
## SN1 -> SN 0.361 0.362 0.006 62.066 0.352 0.371
## SN2 -> SN 0.345 0.345 0.004 77.384 0.338 0.353
## SN3 -> SN 0.366 0.366 0.006 58.053 0.356 0.377
## PBC2 -> PBC 0.562 0.563 0.014 39.221 0.540 0.587
## PBC3 -> PBC 0.558 0.558 0.014 40.431 0.536 0.581
## WL1 -> WL 0.235 0.235 0.010 23.279 0.218 0.251
## WL2 -> WL 0.342 0.342 0.009 39.198 0.328 0.357
## WL3 -> WL 0.256 0.256 0.009 29.737 0.242 0.270
## WL4 -> WL 0.360 0.360 0.010 34.994 0.344 0.377
##
## Bootstrapped Loadings:
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 5% CI 95% CI
## PI1 -> PI 0.954 0.954 0.005 202.816 0.945 0.961
## PI2 -> PI 0.961 0.961 0.004 258.310 0.955 0.967
## PI3 -> PI 0.946 0.946 0.006 156.868 0.935 0.955
## ATT1 -> ATT 0.951 0.951 0.004 223.992 0.944 0.958
## ATT2 -> ATT 0.939 0.939 0.009 109.967 0.924 0.952
## ATT3 -> ATT 0.905 0.905 0.010 92.791 0.888 0.920
## SN1 -> SN 0.929 0.929 0.006 145.913 0.918 0.939
## SN2 -> SN 0.943 0.943 0.006 158.865 0.932 0.952
## SN3 -> SN 0.926 0.926 0.007 132.919 0.914 0.937
## PBC2 -> PBC 0.893 0.893 0.010 93.707 0.877 0.908
## PBC3 -> PBC 0.891 0.891 0.010 87.299 0.873 0.906
## WL1 -> WL 0.743 0.742 0.024 30.779 0.701 0.780
## WL2 -> WL 0.899 0.899 0.008 117.553 0.885 0.910
## WL3 -> WL 0.796 0.796 0.019 41.784 0.762 0.826
## WL4 -> WL 0.873 0.873 0.009 96.143 0.858 0.888
##
## Bootstrapped HTMT:
## Original Est. Bootstrap Mean Bootstrap SD 5% CI 95% CI
## ATT -> SN 0.643 0.643 0.025 0.601 0.683
## ATT -> PBC 0.743 0.744 0.029 0.695 0.790
## ATT -> WL 0.668 0.668 0.030 0.616 0.716
## ATT -> PI 0.713 0.713 0.023 0.673 0.750
## SN -> PBC 0.754 0.754 0.028 0.707 0.799
## SN -> WL 0.664 0.664 0.028 0.618 0.708
## SN -> PI 0.696 0.696 0.024 0.656 0.734
## PBC -> WL 0.787 0.787 0.031 0.735 0.837
## PBC -> PI 0.804 0.804 0.025 0.763 0.844
## WL -> PI 0.864 0.864 0.016 0.836 0.889
##
## Bootstrapped Total Paths:
## Original Est. Bootstrap Mean Bootstrap SD 5% CI 95% CI
## ATT -> PI 0.182 0.183 0.028 0.136 0.230
## SN -> PI 0.152 0.152 0.032 0.099 0.204
## PBC -> PI 0.157 0.156 0.033 0.103 0.210
## WL -> PI 0.493 0.493 0.033 0.437 0.547
# use tstat and CI from Bootstrapped Structural Paths results to check which is significant
# inspect the items VIF
summary_simple$validity$vif_items # CONCLUSION: PI1 and PI2 has VIF > 5, So presence of multicollinearity problems (not good)
## ATT :
## ATT1 ATT2 ATT3
## 4.792 4.197 2.798
##
## SN :
## SN1 SN2 SN3
## 3.473 4.223 3.270
##
## PBC :
## PBC2 PBC3
## 1.54 1.54
##
## WL :
## WL1 WL2 WL3 WL4
## 1.638 2.747 1.841 2.386
##
## PI :
## PI1 PI2 PI3
## 5.277 5.977 4.389
summary_simple$vif_antecedents # CONCLUSION: all constructs VIF < 5, So absence of multicollinearity problems (good)
## PI :
## ATT SN PBC WL
## 1.973 1.976 2.141 2.034
# to inspect specific significance direct effects
summary_boot$bootstrapped_paths #path coefficent is sig at 5% if there is no zeros in between the CI
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 5% CI 95% CI
## ATT -> PI 0.182 0.183 0.028 6.409 0.136 0.230
## SN -> PI 0.152 0.152 0.032 4.764 0.099 0.204
## PBC -> PI 0.157 0.156 0.033 4.787 0.103 0.210
## WL -> PI 0.493 0.493 0.033 14.719 0.437 0.547
# to inspect the Bootstrapped Structural loadings
summary_boot$bootstrapped_loadings
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 5% CI 95% CI
## PI1 -> PI 0.954 0.954 0.005 202.816 0.945 0.961
## PI2 -> PI 0.961 0.961 0.004 258.310 0.955 0.967
## PI3 -> PI 0.946 0.946 0.006 156.868 0.935 0.955
## ATT1 -> ATT 0.951 0.951 0.004 223.992 0.944 0.958
## ATT2 -> ATT 0.939 0.939 0.009 109.967 0.924 0.952
## ATT3 -> ATT 0.905 0.905 0.010 92.791 0.888 0.920
## SN1 -> SN 0.929 0.929 0.006 145.913 0.918 0.939
## SN2 -> SN 0.943 0.943 0.006 158.865 0.932 0.952
## SN3 -> SN 0.926 0.926 0.007 132.919 0.914 0.937
## PBC2 -> PBC 0.893 0.893 0.010 93.707 0.877 0.908
## PBC3 -> PBC 0.891 0.891 0.010 87.299 0.873 0.906
## WL1 -> WL 0.743 0.742 0.024 30.779 0.701 0.780
## WL2 -> WL 0.899 0.899 0.008 117.553 0.885 0.910
## WL3 -> WL 0.796 0.796 0.019 41.784 0.762 0.826
## WL4 -> WL 0.873 0.873 0.009 96.143 0.858 0.888
# to inspect the r^square
summary_simple$paths # check for direct effects
## PI
## R^2 0.718
## AdjR^2 0.717
## ATT 0.182
## SN 0.152
## PBC 0.157
## WL 0.493
# CONCLUSION: PI model,R2 =0.718; paths coefficients: ATT=0.182, PBC=0.157, SN=0.157,WFL = 0.493
# inspect the effect size
### 0.00 - 0.02 = No/very weak effect
### 0.02 to 0.15 = Small effect
### 0.15 to 0.35 = Medium effect
### 0.35 to 0.50 = Large effect
summary_simple$fSquare #CONCLUSION: large effect (WFL),medium (), small(ATT,SN,PBC), no/very weak()
## ATT SN PBC WL PI
## ATT 0.000 0.000 0.000 0.000 0.059
## SN 0.000 0.000 0.000 0.000 0.041
## PBC 0.000 0.000 0.000 0.000 0.041
## WL 0.000 0.000 0.000 0.000 0.422
## PI 0.000 0.000 0.000 0.000 0.000
predict_model<- predict_pls(
model=simple_model,
technique = predict_DA,
noFolds = 10,
reps = 10
)
# compare PLS out-of-sample metrics: to LM out-of-sample metrics
# summarise the prediction results
summary_predict<- summary(predict_model)
summary_predict
##
## PLS in-sample metrics:
## PI1 PI2 PI3
## RMSE 0.591 0.573 0.575
## MAE 0.431 0.418 0.419
##
## PLS out-of-sample metrics:
## PI1 PI2 PI3
## RMSE 0.596 0.577 0.579
## MAE 0.434 0.420 0.421
##
## LM in-sample metrics:
## PI1 PI2 PI3
## RMSE 0.567 0.554 0.559
## MAE 0.411 0.401 0.406
##
## LM out-of-sample metrics:
## PI1 PI2 PI3
## RMSE 0.582 0.570 0.572
## MAE 0.421 0.409 0.413
##
## Construct Level metrics:
## PI
## IS_MSE 1.7326
## IS_MAE 1.0274
## OOS_MSE 1.7375
## OOS_MAE 1.0282
## overfit 0.0028
# Conclusion PLSpredict indicates that while the model explains purchase intention well in-sample, it shows limited out-of-sample predictive accuracy and does not outperform the linear benchmark, which is typical for attitudinal intention models.
library(moments)
# All indicators
indicators <- c(paste0("PI",1:3), paste0("ATT",1:3), paste0("SN",1:3),
paste0("PBC",2:3), paste0("WL",1:4))
# Skewness
skew_values <- sapply(my_data[indicators], skewness, na.rm = TRUE)
# mostly moderate negative skew.
# Shapiro-Wilk p-values
shapiro_p <- sapply(my_data[indicators], function(x) shapiro.test(x)$p.value)
# All p-values are extremely small (< 0.05). all indicators are “statistically non-normal”, but this is normal in large samples.
# Combine results
results <- data.frame(Indicator = indicators, Skewness = skew_values, Shapiro_p = shapiro_p)
print(results) #Shapiro-Wilk is not reliable for large N — rely on skewness and practical judgment.
## Indicator Skewness Shapiro_p
## PI1 PI1 -0.5820863 1.437934e-27
## PI2 PI2 -0.5771280 2.198353e-27
## PI3 PI3 -0.6367268 6.417538e-28
## ATT1 ATT1 -0.5219598 1.734718e-28
## ATT2 ATT2 -0.5580303 1.969654e-28
## ATT3 ATT3 -0.3746609 2.241768e-29
## SN1 SN1 -0.1590990 1.315768e-27
## SN2 SN2 -0.1878545 2.464034e-29
## SN3 SN3 -0.2787749 3.100212e-30
## PBC2 PBC2 -0.1807918 5.620343e-29
## PBC3 PBC3 -0.2006717 3.553573e-27
## WL1 WL1 -0.5945917 5.461892e-27
## WL2 WL2 -0.6531834 4.989517e-28
## WL3 WL3 -0.4675625 6.031396e-26
## WL4 WL4 -0.6202800 5.381864e-28
#RESULTS:All indicators showed slight negative skewness. Shapiro–Wilk tests indicated non-normal distributions (p < .001)
# Recommendation: Use MAE for PLSpredict metrics and interpret with skewness in mind.
####OR PLOT TO CHECK SKEWNESS#####
## to plot and see for each indicators
par(mfrow=c(1,2))
plot(summary_predict,
indicator = "PI2")
plot(summary_predict,
indicator = "PI3")
par(mfrow=c(1,1))
# inspect the construct loadings metrics:ideally be ≥ 0.70, with 0.60–0.70 acceptable and < 0.60 considered problematic.
summary_simple$loadings #(indicator loading should be > 0.708)
## ATT SN PBC WL PI
## PI1 0.000 0.000 0.000 0.000 0.954
## PI2 0.000 0.000 0.000 0.000 0.961
## PI3 0.000 0.000 0.000 0.000 0.946
## ATT1 0.951 0.000 0.000 0.000 0.000
## ATT2 0.939 0.000 0.000 0.000 0.000
## ATT3 0.905 0.000 0.000 0.000 0.000
## SN1 0.000 0.929 0.000 0.000 0.000
## SN2 0.000 0.943 0.000 0.000 0.000
## SN3 0.000 0.926 0.000 0.000 0.000
## PBC2 0.000 0.000 0.893 0.000 0.000
## PBC3 0.000 0.000 0.891 0.000 0.000
## WL1 0.000 0.000 0.000 0.743 0.000
## WL2 0.000 0.000 0.000 0.899 0.000
## WL3 0.000 0.000 0.000 0.796 0.000
## WL4 0.000 0.000 0.000 0.873 0.000
# Conclusion: all indicators are >0.708
summary_simple$loadings^2 #(indicator reliability should be>0.5)
## ATT SN PBC WL PI
## PI1 0.000 0.000 0.000 0.000 0.909
## PI2 0.000 0.000 0.000 0.000 0.924
## PI3 0.000 0.000 0.000 0.000 0.895
## ATT1 0.905 0.000 0.000 0.000 0.000
## ATT2 0.882 0.000 0.000 0.000 0.000
## ATT3 0.819 0.000 0.000 0.000 0.000
## SN1 0.000 0.863 0.000 0.000 0.000
## SN2 0.000 0.889 0.000 0.000 0.000
## SN3 0.000 0.857 0.000 0.000 0.000
## PBC2 0.000 0.000 0.798 0.000 0.000
## PBC3 0.000 0.000 0.795 0.000 0.000
## WL1 0.000 0.000 0.000 0.552 0.000
## WL2 0.000 0.000 0.000 0.807 0.000
## WL3 0.000 0.000 0.000 0.634 0.000
## WL4 0.000 0.000 0.000 0.762 0.000
# Conclusion: all indicators are > 0.5. No issues of non-reliability of indicators
# to inspect composite reliability rhoc of estimated model
summary_simple$reliability ### Note: only PBC has alpha<0.7 in the original model (not good);so PBC1 was removed
## alpha rhoC AVE rhoA
## ATT 0.924 0.952 0.869 0.927
## SN 0.925 0.952 0.870 0.926
## PBC 0.744 0.886 0.796 0.744
## WL 0.850 0.898 0.689 0.879
## PI 0.950 0.968 0.909 0.950
##
## Alpha, rhoC, and rhoA should exceed 0.7 while AVE should exceed 0.5
# rhoa values should be between alpha and rhoc
# Conclusion : all are relaible
# to plot reliability chart
plot(summary_simple$reliability) #horizontal blue line is the threshold
# STEP 3: Assess the convergent validity - Validity assessment is AVE. -
Average variance extracted (AVE) = SUM OF SQUARED LOADINGS/NO OF
INDICATORS (>=0.50 is acceptable).
summary_simple$reliability # Conclusion: all AVE values are > 0.5:good
## alpha rhoC AVE rhoA
## ATT 0.924 0.952 0.869 0.927
## SN 0.925 0.952 0.870 0.926
## PBC 0.744 0.886 0.796 0.744
## WL 0.850 0.898 0.689 0.879
## PI 0.950 0.968 0.909 0.950
##
## Alpha, rhoC, and rhoA should exceed 0.7 while AVE should exceed 0.5
summary_simple$validity$fl_criteria #first value in each column should be higher than other values below
## ATT SN PBC WL PI
## ATT 0.932 . . . .
## SN 0.595 0.933 . . .
## PBC 0.616 0.626 0.892 . .
## WL 0.608 0.598 0.634 0.830 .
## PI 0.669 0.653 0.676 0.794 0.954
##
## FL Criteria table reports square root of AVE on the diagonal and construct correlations on the lower triangle.
# to inspect Henseler proposal
summary_simple$validity$htmt #all of the values should be <0.90
## ATT SN PBC WL PI
## ATT . . . . .
## SN 0.643 . . . .
## PBC 0.743 0.754 . . .
## WL 0.668 0.664 0.787 . .
## PI 0.713 0.696 0.804 0.864 .
summary_simple$validity$cross_loadings #loadings values for each indicators should be the highest at its own construct and not other constructs
## ATT SN PBC WL PI
## PI1 0.630 0.614 0.631 0.751 0.954
## PI2 0.628 0.624 0.647 0.768 0.961
## PI3 0.655 0.630 0.655 0.752 0.946
## ATT1 0.951 0.561 0.574 0.585 0.642
## ATT2 0.939 0.571 0.569 0.570 0.635
## ATT3 0.905 0.533 0.580 0.545 0.591
## SN1 0.592 0.929 0.593 0.559 0.615
## SN2 0.524 0.943 0.564 0.545 0.588
## SN3 0.548 0.926 0.593 0.568 0.623
## PBC2 0.584 0.542 0.893 0.587 0.605
## PBC3 0.515 0.575 0.891 0.543 0.601
## WL1 0.371 0.395 0.429 0.743 0.508
## WL2 0.582 0.550 0.571 0.899 0.739
## WL3 0.409 0.453 0.487 0.796 0.554
## WL4 0.603 0.559 0.591 0.873 0.777
# extract bootstrapped htmt
summary_boot$bootstrapped_HTMT #there should be no 1 in the CI=NO ISSUES OF DISCRIMINALITY
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 5% CI 95% CI
## ATT -> SN 0.643 0.643 0.025 25.724 0.601 0.683
## ATT -> PBC 0.743 0.744 0.029 25.601 0.695 0.790
## ATT -> WL 0.668 0.668 0.030 21.966 0.616 0.716
## ATT -> PI 0.713 0.713 0.023 30.341 0.673 0.750
## SN -> PBC 0.754 0.754 0.028 26.780 0.707 0.799
## SN -> WL 0.664 0.664 0.028 24.060 0.618 0.708
## SN -> PI 0.696 0.696 0.024 29.249 0.656 0.734
## PBC -> WL 0.787 0.787 0.031 25.409 0.735 0.837
## PBC -> PI 0.804 0.804 0.025 32.760 0.763 0.844
## WL -> PI 0.864 0.864 0.016 52.547 0.836 0.889
# exporitng
# write.csv(x=summary_boot$bootstrapped_loadings, file = "boot_loadings.csv")
# to plot the constructs' internal consistency reliabilities
plot(summary_simple$reliability)
# to plot pls estimated model
plot(simple_model)
# to plot bootstrapped pls estimated model
plot(boot_simple) #shows the significant variables
# to create reflective mm (no need to write mode_A)
simple_mm<- constructs(
composite("PI", multi_items("PI",1:3)),
composite("ATT", multi_items("ATT",1:3)),
composite("SN", multi_items("SN",1:3)),
composite("PBC", multi_items("PBC",2:3)), #PBC1 was removed because loading=0.540 and alpha< 0.7its removal has a better effect on reliability and validity metrics/content validity (<0.708 recommendation limit)
composite("WL", multi_items("WL",1:4))
)
simple_mm
## $composite
## [1] "PI" "PI1" "A" "PI" "PI2" "A" "PI" "PI3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "ATT" "ATT1" "A" "ATT" "ATT2" "A" "ATT" "ATT3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "SN" "SN1" "A" "SN" "SN2" "A" "SN" "SN3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "PBC" "PBC2" "A" "PBC" "PBC3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "WL" "WL1" "A" "WL" "WL2" "A" "WL" "WL3" "A" "WL" "WL4" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## attr(,"class")
## [1] "list" "measurement_model" "seminr_model"
# to create sm for indirect efffects
simple_sm <- relationships(
paths(from = c("ATT","SN","PBC","WL"), to = "PI"),
paths(from = "WL", to = c("ATT","SN","PBC"))
)
simple_sm
## source target
## [1,] "ATT" "PI"
## [2,] "SN" "PI"
## [3,] "PBC" "PI"
## [4,] "WL" "PI"
## [5,] "WL" "ATT"
## [6,] "WL" "SN"
## [7,] "WL" "PBC"
## attr(,"class")
## [1] "matrix" "array" "structural_model" "seminr_model"
# to estimate the model
simple_model <- estimate_pls(data = my_data,
measurement_model = simple_mm,
structural_model = simple_sm,
inner_weights = path_weighting,
missing = mean_replacement,
missing_value = "-99"
)
## Generating the seminr model
## All 999 observations are valid.
# summary()
summary_simple <- summary(simple_model) #shows the path coefficients and reliability
plot(simple_model) #β IS PATH COEFFICIENT ; λ IS outer loadings
summary_simple$total_indirect_effects
## ATT SN PBC WL PI
## ATT 0.000 0.000 0.000 0.000 0.000
## SN 0.000 0.000 0.000 0.000 0.000
## PBC 0.000 0.000 0.000 0.000 0.000
## WL 0.000 0.000 0.000 0.000 0.302
## PI 0.000 0.000 0.000 0.000 0.000
# Conclusion: Only AFF shows a non-zero indirect effect on Purchase Intention (PI) (β = 0.269), indicating the presence of mediation
boot_simple <- bootstrap_model(
seminr_model = simple_model,
nboot = 10000,
cores = NULL,
seed = 123
)
## Bootstrapping model using seminr...
## SEMinR Model successfully bootstrapped
distal <- "WL"
mediators <- c("ATT","SN","PBC")
target <- "PI"
for (f in distal) for (m in mediators) {
specific_effect_significance(boot_simple, from = f, through = m, to = target, alpha = 0.05)
}
lapply(c("ATT","SN","PBC"), function(m) specific_effect_significance(boot_simple, from="WL", through=m, to="PI", alpha=0.05))
## [[1]]
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 2.5% CI
## 0.11120463 0.11193332 0.01900359 5.85176806 0.07574051
## 97.5% CI
## 0.15075745
##
## [[2]]
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 2.5% CI
## 0.09139521 0.09130059 0.01940342 4.71026182 0.05385709
## 97.5% CI
## 0.12908554
##
## [[3]]
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 2.5% CI
## 0.09947129 0.09919270 0.02109589 4.71519833 0.05763380
## 97.5% CI
## 0.14023741
# to inspect indirect effects
summary_boot_med<-summary(boot_simple)
summary_boot_med$bootstrapped_paths
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 2.5% CI 97.5% CI
## ATT -> PI 0.183 0.184 0.029 6.406 0.128 0.242
## SN -> PI 0.153 0.153 0.032 4.775 0.091 0.215
## PBC -> PI 0.157 0.157 0.033 4.780 0.092 0.220
## WL -> ATT 0.607 0.607 0.027 22.567 0.552 0.658
## WL -> SN 0.598 0.598 0.025 23.644 0.547 0.646
## WL -> PBC 0.633 0.634 0.025 25.201 0.583 0.681
## WL -> PI 0.490 0.490 0.034 14.504 0.422 0.555
# to inspect direct effects
summary_simple$paths
## PI ATT SN PBC
## R^2 0.717 0.368 0.357 0.401
## AdjR^2 0.716 0.368 0.356 0.401
## ATT 0.183 . . .
## SN 0.153 . . .
## PBC 0.157 . . .
## WL 0.490 0.607 0.598 0.633
# to inspect the confidence intervals for direct effects
summary_boot$bootstrapped_paths #if significant if t-stat >1.96 and there is no zeros between CI, then it shows partial mediation
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 5% CI 95% CI
## ATT -> PI 0.182 0.183 0.028 6.409 0.136 0.230
## SN -> PI 0.152 0.152 0.032 4.764 0.099 0.204
## PBC -> PI 0.157 0.156 0.033 4.787 0.103 0.210
## WL -> PI 0.493 0.493 0.033 14.719 0.437 0.547
# FOR AFF
summary_simple$paths["WL","ATT"]*summary_simple$paths["WL","PI"]*summary_simple$paths["WL","PI"]
## [1] 0.1457166
summary_simple$paths["WL","SN"]*summary_simple$paths["WL","PI"]*summary_simple$paths["WL","PI"]
## [1] 0.1435085
summary_simple$paths["WL","PBC"]*summary_simple$paths["WL","PI"]*summary_simple$paths["WL","PI"]
## [1] 0.1521046
plot(simple_model)
plot(boot_simple)
# create interaction (two-stage recommended for reflective composites)
simple_mm <- constructs(
composite("PI", multi_items("PI",1:3)),
composite("ATT", multi_items("ATT",1:3)),
composite("SN", multi_items("SN",1:3)),
composite("PBC", multi_items("PBC",2:3)),
composite("WL", multi_items("WL",1:4)),
interaction_term(iv = "ATT",moderator = "WL",method = two_stage),
interaction_term(iv = "SN",moderator = "WL",method = two_stage),
interaction_term(iv = "PBC",moderator = "WL",method = two_stage)
)
simple_mm
## $composite
## [1] "PI" "PI1" "A" "PI" "PI2" "A" "PI" "PI3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "ATT" "ATT1" "A" "ATT" "ATT2" "A" "ATT" "ATT3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "SN" "SN1" "A" "SN" "SN2" "A" "SN" "SN3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "PBC" "PBC2" "A" "PBC" "PBC3" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $composite
## [1] "WL" "WL1" "A" "WL" "WL2" "A" "WL" "WL3" "A" "WL" "WL4" "A"
## attr(,"class")
## [1] "character" "construct" "composite"
##
## $two_stage_interaction
## function (data, mmMatrix, structural_model, ints, estimate_first_stage,
## ...)
## {
## interaction_name <- paste(iv, moderator, sep = "*")
## structural_model <- structural_model[!grepl("\\*", structural_model[,
## "source"]), ]
## measurement_mode_scheme <- sapply(unique(c(structural_model[,
## 1], structural_model[, 2])), get_measure_mode, mmMatrix,
## USE.NAMES = TRUE)
## first_stage <- estimate_first_stage(data = data, smMatrix = structural_model,
## mmMatrix = mmMatrix, measurement_mode_scheme = measurement_mode_scheme,
## ...)
## interaction_term <- as.matrix(first_stage$construct_scores[,
## iv] * first_stage$construct_scores[, moderator], ncol = 1)[,
## , drop = FALSE]
## colnames(interaction_term) <- c(paste(interaction_name, "_intxn",
## sep = ""))
## intxn_mm <- matrix(measure_interaction(interaction_name,
## interaction_term, weights), ncol = 3, byrow = TRUE)
## return(list(name = interaction_name, data = interaction_term[,
## 1, drop = FALSE], mm = intxn_mm))
## }
## <bytecode: 0x0000018446d54518>
## <environment: 0x0000018446d52e70>
## attr(,"class")
## [1] "function" "interaction" "two_stage_interaction"
##
## $two_stage_interaction
## function (data, mmMatrix, structural_model, ints, estimate_first_stage,
## ...)
## {
## interaction_name <- paste(iv, moderator, sep = "*")
## structural_model <- structural_model[!grepl("\\*", structural_model[,
## "source"]), ]
## measurement_mode_scheme <- sapply(unique(c(structural_model[,
## 1], structural_model[, 2])), get_measure_mode, mmMatrix,
## USE.NAMES = TRUE)
## first_stage <- estimate_first_stage(data = data, smMatrix = structural_model,
## mmMatrix = mmMatrix, measurement_mode_scheme = measurement_mode_scheme,
## ...)
## interaction_term <- as.matrix(first_stage$construct_scores[,
## iv] * first_stage$construct_scores[, moderator], ncol = 1)[,
## , drop = FALSE]
## colnames(interaction_term) <- c(paste(interaction_name, "_intxn",
## sep = ""))
## intxn_mm <- matrix(measure_interaction(interaction_name,
## interaction_term, weights), ncol = 3, byrow = TRUE)
## return(list(name = interaction_name, data = interaction_term[,
## 1, drop = FALSE], mm = intxn_mm))
## }
## <bytecode: 0x0000018446d54518>
## <environment: 0x0000018446d41f80>
## attr(,"class")
## [1] "function" "interaction" "two_stage_interaction"
##
## $two_stage_interaction
## function (data, mmMatrix, structural_model, ints, estimate_first_stage,
## ...)
## {
## interaction_name <- paste(iv, moderator, sep = "*")
## structural_model <- structural_model[!grepl("\\*", structural_model[,
## "source"]), ]
## measurement_mode_scheme <- sapply(unique(c(structural_model[,
## 1], structural_model[, 2])), get_measure_mode, mmMatrix,
## USE.NAMES = TRUE)
## first_stage <- estimate_first_stage(data = data, smMatrix = structural_model,
## mmMatrix = mmMatrix, measurement_mode_scheme = measurement_mode_scheme,
## ...)
## interaction_term <- as.matrix(first_stage$construct_scores[,
## iv] * first_stage$construct_scores[, moderator], ncol = 1)[,
## , drop = FALSE]
## colnames(interaction_term) <- c(paste(interaction_name, "_intxn",
## sep = ""))
## intxn_mm <- matrix(measure_interaction(interaction_name,
## interaction_term, weights), ncol = 3, byrow = TRUE)
## return(list(name = interaction_name, data = interaction_term[,
## 1, drop = FALSE], mm = intxn_mm))
## }
## <bytecode: 0x0000018446d54518>
## <environment: 0x0000018446d43120>
## attr(,"class")
## [1] "function" "interaction" "two_stage_interaction"
##
## attr(,"class")
## [1] "list" "measurement_model" "seminr_model"
simple_sm <- relationships(
paths(from = c("ATT","SN","PBC","WL","ATT*WL","SN*WL","PBC*WL"), to = "PI")
)
simple_sm
## source target
## [1,] "ATT" "PI"
## [2,] "SN" "PI"
## [3,] "PBC" "PI"
## [4,] "WL" "PI"
## [5,] "ATT*WL" "PI"
## [6,] "SN*WL" "PI"
## [7,] "PBC*WL" "PI"
## attr(,"class")
## [1] "matrix" "array" "structural_model" "seminr_model"
simple_mod_model <- estimate_pls(data = my_data,simple_mm,simple_sm
)
## Generating the seminr model
## All 999 observations are valid.
# to summarise
summary_mod_simple <- summary(simple_mod_model)
summary_mod_simple
##
## Results from package seminr (2.3.7)
##
## Path Coefficients:
## PI
## R^2 0.720
## AdjR^2 0.718
## ATT 0.174
## SN 0.149
## PBC 0.162
## WL 0.486
## ATT*WL -0.038
## SN*WL 0.005
## PBC*WL 0.001
##
## Reliability:
## alpha rhoC AVE rhoA
## ATT 0.924 0.952 0.869 0.927
## SN 0.925 0.952 0.870 0.926
## PBC 0.744 0.886 0.796 0.744
## WL 0.850 0.898 0.689 0.879
## ATT*WL 1.000 1.000 1.000 1.000
## SN*WL 1.000 1.000 1.000 1.000
## PBC*WL 1.000 1.000 1.000 1.000
## PI 0.950 0.968 0.909 0.950
##
## Alpha, rhoC, and rhoA should exceed 0.7 while AVE should exceed 0.5
boot_mod_simple <- bootstrap_model(
seminr_model = simple_mod_model,
nboot = 10000,
cores = NULL,
seed = 123
)
## Bootstrapping model using seminr...
## SEMinR Model successfully bootstrapped
# to inspect bootstrapped paths
summary_mod_boot<-summary(boot_mod_simple, alpha=0.05)
summary_mod_boot$bootstrapped_paths
## Original Est. Bootstrap Mean Bootstrap SD T Stat. 2.5% CI
## ATT -> PI 0.174 0.176 0.028 6.172 0.122
## SN -> PI 0.149 0.149 0.032 4.676 0.086
## PBC -> PI 0.162 0.162 0.033 4.949 0.098
## WL -> PI 0.486 0.486 0.033 14.590 0.419
## ATT*WL -> PI -0.038 -0.037 0.025 -1.504 -0.086
## SN*WL -> PI 0.005 0.004 0.024 0.190 -0.044
## PBC*WL -> PI 0.001 0.001 0.022 0.043 -0.042
## 97.5% CI
## ATT -> PI 0.232
## SN -> PI 0.210
## PBC -> PI 0.225
## WL -> PI 0.550
## ATT*WL -> PI 0.012
## SN*WL -> PI 0.052
## PBC*WL -> PI 0.043
#significant ATT*WFL -> PI has -0.033 and ATT -> PI has 0.174
#Interpretation: The interaction term-ATT*WFL has a -ve effect on PI, While the simple effect ATT is +VE for average level of WFL
#Lower levels of WFL (for every standard deviation unit decrease of WFL), the relationship between ATT and PI increases the size of the interaction term(i.e 0.174-(-0.033)=0.207)
# Extract R2 values
r2_included <- summary_mod_simple$paths
# = 0.750
r2_excluded <- summary_simple$paths
# =0.744
# Calculate f2
f2 = (0.750 - 0.744) / (1 - 0.750)
f2 #0.024
## [1] 0.024
#use kenny 2018 proposition to determine effects
slope_analysis(moderated_model = simple_mod_model,
dv="PI",
moderator = "WL",
iv="ATT",
leg_place = "bottomright")
# check the steepness of the curve
slope_analysis(moderated_model = simple_mod_model,
dv="PI",
moderator = "WL",
iv="SN",
leg_place = "bottomright")
# check the steepness of the curve
slope_analysis(moderated_model = simple_mod_model,
dv="PI",
moderator = "WL",
iv="PBC",
leg_place = "bottomright")
# check the steepness of the curve
set.seed(123)
n_sim <- 10000
n_sim
## [1] 10000
✔ These preserve skewness and non-normality ✔ No distributional assumptions - Hypotheses addressed: i) MC-H1: Stability of ATT → PI ii) MC-H2: Stability of SN → PI iii) MC-H3: Stability of PBC → PI iv) MC-H4: Stability of WL → PI - Why: Defines the estimated TPB and labelling effects to be tested for robustness.
# Since we only have the bootstrap means, create vectors by repeating the mean
# This avoids assuming normality, but note: ideally we would use full 10,000 bootstrap resamples
# Create empirical bootstrap-based distributions
# Using 5%–95% bootstrap CIs (no normality assumption)
boot_beta_ATT <- runif(n_sim, min = 0.136, max = 0.230) # ATT -> PI
boot_beta_SN <- runif(n_sim, min = 0.099, max = 0.204) # SN -> PI
boot_beta_PBC <- runif(n_sim, min = 0.103, max = 0.210) # PBC -> PI
boot_beta_WFL <- runif(n_sim, min = 0.437, max = 0.547) # WL -> PI
✔ This is the key correction for non-normal data ✔ Hypotheses addressed: i) MC-H1 to MC-H4 (all) - Why: Tests whether the estimated effects remain stable under repeated resampling (Monte Carlo logic).
beta_ATT <- sample(boot_beta_ATT, n_sim, replace = TRUE)
beta_PBC <- sample(boot_beta_PBC, n_sim, replace = TRUE)
beta_SN <- sample(boot_beta_SN, n_sim, replace = TRUE)
beta_WFL <- sample(boot_beta_WFL, n_sim, replace = TRUE)
# Step 4: Simulate Purchase Intention
PI_sim <- beta_ATT +beta_PBC +beta_SN + beta_WFL
# Step 5: Summary statistics
summary(PI_sim)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.7960 0.9402 0.9818 0.9823 1.0245 1.1737
# Uncertainty range
quantile(PI_sim, probs = c(0.05, 0.50, 0.95))
## 5% 50% 95%
## 0.8839176 0.9818230 1.0819442
# Conclusion: Monte Carlo simulations based on bootstrap confidence intervals indicate that the combined effects of attitude, subjective norms, perceived behavioral control, and water footprint labelling on purchase intention remain positive and stable, with a 90% uncertainty interval of [0.884, 1.084].
# Probability that Purchase Intention is positive
mean(PI_sim > 0)
## [1] 1
# Monte Carlo simulations indicate a 100% probability that purchase intention remains positive, confirming the robustness of the extended TPB model under non-normal data conditions.