# ########## Moderation/Mediation Partial Least Squares Path Model. # # To see the model we're working with below, paste the following into # your browser: # http://www.unt.edu/rss/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://www.unt.edu/rss/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.