#
########## Moderation/Mediation Partial Least Squares Path Model.
#
# To see the model we're working with below, paste the following into
# your browser:
# http://researchsupport.unt.edu/class/Jon/R_SC/Module8/PLS_ModMed_Model_1.pdf
## <<< Data Generation Begin >>>
n <- 1000
######## Group 1 population (pop.grp.1) data creation.
# Create the latent variables and the relationships between them (i.e. path coefficients).
x <- rnorm(n)
m <- .6*x + rnorm(n,0,sqrt(1 - (.6^2)))
y <- .4*x + .7*m + rnorm(n,0,sqrt(1 - (.7^2)))
# Create (manifest/indicator) variables (data array).
v1 <- .8*x + rnorm(n,0,sqrt(1 - (.8^2)))
v2 <- .8*x + rnorm(n,0,sqrt(1 - (.8^2)))
v3 <- .8*x + rnorm(n,0,sqrt(1 - (.8^2)))
v4 <- .8*x + rnorm(n,0,sqrt(1 - (.8^2)))
v5 <- .7*m + rnorm(n,0,sqrt(1 - (.7^2)))
v6 <- .7*m + rnorm(n,0,sqrt(1 - (.7^2)))
v7 <- .7*m + rnorm(n,0,sqrt(1 - (.7^2)))
v8 <- .7*m + rnorm(n,0,sqrt(1 - (.7^2)))
v9 <- .6*y + rnorm(n,0,sqrt(1 - (.6^2)))
v10 <- .6*y + rnorm(n,0,sqrt(1 - (.6^2)))
v11 <- .6*y + rnorm(n,0,sqrt(1 - (.6^2)))
v12 <- .6*y + rnorm(n,0,sqrt(1 - (.6^2)))
# Put it all into a data frame.
pop.grp.1 <- data.frame(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12)
rm(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,x,m,y)
######## Group 2 population (pop.grp.2) data creation.
# Create the latent variables and the relationships between them (i.e. path coefficients).
x <- rnorm(n)
m <- .4*x + rnorm(n,0,sqrt(1 - (.6^2)))
y <- .7*x + .5*m + rnorm(n,0,sqrt(1 - (.7^2)))
# Create (manifest/indicator) variables (data array).
v1 <- .8*x + rnorm(n,0,sqrt(1 - (.8^2)))
v2 <- .8*x + rnorm(n,0,sqrt(1 - (.8^2)))
v3 <- .8*x + rnorm(n,0,sqrt(1 - (.8^2)))
v4 <- .8*x + rnorm(n,0,sqrt(1 - (.8^2)))
v5 <- .7*m + rnorm(n,0,sqrt(1 - (.7^2)))
v6 <- .7*m + rnorm(n,0,sqrt(1 - (.7^2)))
v7 <- .7*m + rnorm(n,0,sqrt(1 - (.7^2)))
v8 <- .7*m + rnorm(n,0,sqrt(1 - (.7^2)))
v9 <- .6*y + rnorm(n,0,sqrt(1 - (.6^2)))
v10 <- .6*y + rnorm(n,0,sqrt(1 - (.6^2)))
v11 <- .6*y + rnorm(n,0,sqrt(1 - (.6^2)))
v12 <- .6*y + rnorm(n,0,sqrt(1 - (.6^2)))
# Put it all into a data frame.
pop.grp.2 <- data.frame(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12)
rm(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,x,m,y)
# Putting the groups together into a global population data set (pop) by
# "row binding" the two groups (i.e. one group ontop of the other).
pop <- rbind(pop.grp.1, pop.grp.2)
rm(pop.grp.1, pop.grp.2)
## <<< Data Generation End >>>
################################################################################
# First, establish the moderation effect (i.e. are the two groups different?).
# In order to do so, we must create a factor (variable) which indicates which
# cases belong to each group (1 & 2); which is easy here because group 1 consists
# of the first n = 1000 cases and group 2 is the second n = 1000 cases.
group <- factor(c(rep(1, n), rep(2, n)))
# Now conduct the "grouped" Partial Least Squares path analysis with grouped testing.
library(plspm)
inner.matrix <- matrix(c(0,0,0, 1,0,0, 1,1,0), 3, 3, byrow = TRUE)
dimnames(inner.matrix) <- list(c("X","M","Y"),c("X","M","Y"))
outer.list <- list(c(1,2,3,4), c(5,6,7,8), c(9,10,11,12))
mode.vec <- c("A", "A", "A")
pop.model <- plspm(Data = pop, path_matrix = inner.matrix, blocks = outer.list,
modes = mode.vec, scheme = "centroid", scaled = TRUE,
tol = 0.00001, maxiter = 1000)
plot(pop.model)
grp.tests <- plspm.groups(pls = pop.model, g = group, Y = NULL,
method = "bootstrap", reps = 1000)
grp.tests
ls()
rm(group, grp.tests, pop.model); graphics.off()
ls()
################################################################################
# Second, now that we have established that the two groups are indeed different,
# (i.e. significantly different X -> Y paths) we need to assess the mediation
# effect of "M" on the relationship between "X" and "Y" for each group (i.e.
# group 1, then group 2).
# First, split the two groups into two separate data frames.
group1 <- pop[1:1000,]
group2 <- pop[1001:2000,]
#### GROUP 1: Mediation.
# We start by running the bootstrapped PLS model with group 1 -- to get the
# mean (bootstrapped mean) path coefficients and their standard errors.
grp1.model <- plspm(Data = group1, path_matrix = inner.matrix,
blocks = outer.list, modes = mode.vec, scheme = "centroid", scaled = TRUE,
boot.val = TRUE, br = 1000, tol = 0.00001, maxiter = 1000)
summary(grp1.model)
# We need four numbers from the above summary; and we plug those into a fairly
# simple equation.
# To check mediation, one must conduct a z-test of the paths. A function is created
# below for this purpose. The equations below are from a presentation of:
# Henseler, J., Ringle, C. M., & Sinkovices, R. R. (2009). The use of Partial Least
# Squares Path Modeling in International Marketing. Advances in International
# Marketing, 20, 277 - 320.
# Presentation available at: http://researchsupport.unt.edu/class/Jon/R_SC/Module8/PLS_MGA.pdf
med.fun <- function(a,b,sa,sb){
z.val <- (a*b)/sqrt((b^2*sa^2)+(a^2*sb^2)+(sa^2*sb^2))
return(z.val)
}
# For the function to work, simply supply the path between X, the predictor, and M,
# the mediator, ("a"); the standard error of that path ("sa"); the path between M, the
# mediator, and Y, the outcome, ("b"); and the standard error of that path ("sb").
# Path 'a' is "X -> M" from the output and path 'b' is "M -> Y" from the output.
# NOTE: the numbers supplied below may be slightly different from each run
# of the scripts above, they are given here simply as an example.
grp1.model$boot
grp1.med.z <- med.fun(a = 0.521, b = 0.455, sa = 0.0163, sb = 0.0171)
grp1.med.z
# How much of the total effect is the indirect effect?
# (a*b)/(a*b)+c
grp1.ind.effect <- (0.521*0.455)/((0.521*0.455) + 0.319)
grp1.ind.effect
# For example if "grp1.ind.effct" = 0.4263 it means, 42.63% of the total effect
# is explained by the indirect effect (i.e. the mediation effect).
#### GROUP 2: Mediation (without all the comments).
grp2.model <- plspm(Data = group2, path_matrix = inner.matrix,
blocks = outer.list, modes = mode.vec, scheme = "centroid", scaled = TRUE,
boot.val = TRUE, br = 1000, tol = 0.00001, maxiter = 1000)
summary(grp2.model)
grp2.model$boot
grp2.med.z <- med.fun(a = 0.362, b = 0.288, sa = 0.0196, sb = 0.0178)
grp2.med.z
grp2.ind.effect <- (0.362*0.288)/((0.362*0.288) + 0.498)
grp2.ind.effect
################################################################################
# Cleaning up.
ls()
rm(group1, group2, grp1.ind.effect, grp1.med.z, grp1.model, grp2.ind.effect,
grp2.med.z, grp2.model, inner.matrix, med.fun, mode.vec, n, outer.list, pop)
ls()
# Detaching package 'plspm' and its dependencies.
detach("package:plspm")
detach("package:amap")
detach("package:diagram")
detach("package:shape")
detach("package:turner")
detach("package:tester")
# End. Nov. 4, 2011; updated on August 4th, 2014.