Skip to content

Commit e28d5cb

Browse files
Change syntax (#125)
* Attends to Issue #121. constructs() returns a list and created interaction() construct type * Not working yet.... * changing parameter names * All three interaction methods working with new syntax * Can assign mode A and mode B to interactions. Working * interactions and higher order construct all working. * Updating tests - but not fixtures. * # Updated tests for new syntax * R CMD Check no warnings errors or notes * # 122
2 parents a5a5da5 + ad179c5 commit e28d5cb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+854
-870
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8-
- Change code syntax to remove interactions() function and add interactions and HOC to composites()
8+
- Change code syntax to remove interactions() method and add interactions and HOC to composites()
99
- Document all the syntax and features
1010

1111
## [0.7.0] - 2019-09-19
@@ -18,13 +18,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- A test for the bootstrap summary return object
1919
- Descriptive statistics for item and construct data
2020
- S3 print method for class "table_output" for printing generic tables
21+
- new method interaction_term() for specifying a interaction construct
22+
- new method interaction() for specifying a interaction construct
2123
- A fSquare function to calculating fSquared
2224
- A test for fSquared function
2325

2426
### Changed
2527
- Fixtures for evaluating bootstrap HTMT for versions of R < 3.6.0
2628
- Changed the R/* file naming to R/estimate_ R/feature_ R/evaluate_ etc.
2729
- Summary S3 method to return data descriptives in summary object
30+
- constructs() method now returns a list with classes
2831
- Changed references to include Cohen (2013)
2932
- Updated vignette to reflect fSquare function
3033

NAMESPACE

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@ export(constructs)
1414
export(correlation_weights)
1515
export(estimate_pls)
1616
export(fSquared)
17-
export(interaction_2stage)
18-
export(interaction_ortho)
19-
export(interaction_scaled)
20-
export(interactions)
17+
export(higher_composite)
18+
export(interaction_term)
2119
export(mode_A)
2220
export(mode_B)
2321
export(multi_items)
22+
export(orthogonal)
2423
export(path_factorial)
2524
export(path_weighting)
2625
export(paths)
2726
export(plot_scores)
27+
export(product_indicator)
2828
export(reflective)
2929
export(regression_weights)
3030
export(relationships)
3131
export(report_paths)
3232
export(rho_A)
3333
export(simplePLS)
3434
export(single_item)
35-
export(two_stage_HOC)
35+
export(two_stage)

R/estimate_bootstrap.R

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#' @usage
2020
#' bootstrap_model(seminr_model, nboot = 500, cores = NULL, seed = NULL, ...)
2121
#'
22-
#' @seealso \code{\link{relationships}} \code{\link{constructs}} \code{\link{paths}} \code{\link{interactions}}
22+
#' @seealso \code{\link{relationships}} \code{\link{constructs}} \code{\link{paths}} \code{\link{interaction_term}}
2323
#'
2424
#' @references Hair, J. F., Hult, G. T. M., Ringle, C. M., and Sarstedt, M. (2017). A Primer on Partial Least Squares
2525
#' Structural Equation Modeling (PLS-SEM), 2nd Ed., Sage: Thousand Oaks.
@@ -31,13 +31,9 @@
3131
#' composite("Image", multi_items("IMAG", 1:5)),
3232
#' composite("Expectation", multi_items("CUEX", 1:3)),
3333
#' composite("Value", multi_items("PERV", 1:2)),
34-
#' composite("Satisfaction", multi_items("CUSA", 1:3))
35-
#' )
36-
#'
37-
#' # interaction constructs must be created after the measurement model is defined
38-
#' mobi_xm <- interactions(
39-
#' interaction_ortho("Image", "Expectation"),
40-
#' interaction_ortho("Image", "Value")
34+
#' composite("Satisfaction", multi_items("CUSA", 1:3)),
35+
#' interaction_term(iv = "Image", moderator = "Expectation", method = orthogonal),
36+
#' interaction_term(iv = "Image", moderator = "Value", method = orthogonal)
4137
#' )
4238
#'
4339
#' # structural model: note that name of the interactions construct should be
@@ -50,7 +46,6 @@
5046
#'
5147
#' seminr_model <- estimate_pls(data = mobi,
5248
#' measurement_model = mobi_mm,
53-
#' interactions = mobi_xm,
5449
#' structural_model = mobi_sm)
5550
#'
5651
#' # Load data, assemble model, and bootstrap
@@ -67,7 +62,6 @@ bootstrap_model <- function(seminr_model, nboot = 500, cores = NULL, seed = NULL
6762
cat("Bootstrapping model using seminr...\n")
6863

6964
# prepare parameters for cluster export (model parameters)
70-
interactions = seminr_model$interactions
7165
d <- seminr_model$rawdata
7266
measurement_model <- seminr_model$raw_measurement_model
7367
structural_model <- seminr_model$smMatrix
@@ -89,14 +83,13 @@ bootstrap_model <- function(seminr_model, nboot = 500, cores = NULL, seed = NULL
8983
if (is.null(seed)) {seed <- sample.int(100000, size = 1)}
9084

9185
# Export variables and functions to cluster
92-
parallel::clusterExport(cl=cl, varlist=c("measurement_model", "interactions", "structural_model", "inner_weights", "getRandomIndex", "d", "HTMT", "seed"), envir=environment())
86+
parallel::clusterExport(cl=cl, varlist=c("measurement_model", "structural_model", "inner_weights", "getRandomIndex", "d", "HTMT", "seed"), envir=environment())
9387

9488
# Function to get PLS estimate results
9589
getEstimateResults <- function(i, d = d) {
9690
set.seed(seed+i)
9791
boot_model <- seminr::estimate_pls(data = d[getRandomIndex(d),],
9892
measurement_model,
99-
interactions,
10093
structural_model,
10194
inner_weights)
10295
boot_htmt <- HTMT(boot_model)

R/estimate_model.R

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,17 @@
88
#' @param measurement_model A source-to-target matrix representing the outer/measurement model,
99
#' generated by \code{constructs}.
1010
#'
11-
#' @param interactions An object of type \code{interactions} as generated by the \code{interactions}
12-
#' method. Default setting is \code{NULL} and can be excluded for models with no interactions.
13-
#'
1411
#' @param structural_model A source-to-target matrix representing the inner/structural model,
1512
#' generated by \code{relationships}.
1613
#'
1714
#' @param inner_weights A parameter declaring which inner weighting scheme should be used
1815
#' path_weighting is default, alternately path_factorial can be used.
1916
#'
2017
#' @usage
21-
#' estimate_pls(data, measurement_model, interactions=NULL, structural_model,
18+
#' estimate_pls(data, measurement_model, structural_model,
2219
#' inner_weights = path_weighting)
2320
#'
24-
#' @seealso \code{\link{relationships}} \code{\link{constructs}} \code{\link{paths}} \code{\link{interactions}}
21+
#' @seealso \code{\link{relationships}} \code{\link{constructs}} \code{\link{paths}} \code{\link{interaction_term}}
2522
#' \code{\link{bootstrap_model}}
2623
#'
2724
#' @examples
@@ -54,53 +51,39 @@
5451
#' summary(mobi_pls)
5552
#' plot_scores(mobi_pls)
5653
#' @export
57-
estimate_pls <- function(data, measurement_model, interactions=NULL, structural_model, inner_weights = path_weighting) {
54+
estimate_pls <- function(data, measurement_model, structural_model, inner_weights = path_weighting) {
5855
cat("Generating the seminr model\n")
59-
warnings(measurement_model, data, structural_model)
6056
data <- stats::na.omit(data)
6157
rawdata <- data
6258
raw_measurement_model <- measurement_model
6359
# Generate first order model if necessary
64-
if ("HOCA" %in% measurement_model[,"type"] | "HOCB" %in% measurement_model[,"type"] ) {
60+
61+
HOCs <- measurement_model[names(measurement_model) == "higher_order_composite"]
62+
63+
if ( length(HOCs)>0 ) {
6564
HOM <- prepare_higher_order_model(data = data,
6665
sm = structural_model,
6766
mm = measurement_model,
68-
ints = interactions,
69-
inners = inner_weights)
67+
inners = inner_weights,
68+
HOCs = HOCs)
7069
measurement_model <- HOM$mm
7170
structural_model <- HOM$sm
7271
data <- HOM$data
7372
}
7473

75-
# Generate interactions
76-
if(!is.null(interactions)) {
77-
# update data with new interaction items
78-
intxns_list <- interactions(data = data,
79-
mm = measurement_model,
80-
sm = structural_model,
81-
ints = interactions,
82-
inners = inner_weights)
83-
get_data <- function(intxn) { intxn$data }
84-
interaction_data <- do.call("cbind", lapply(intxns_list, get_data))
85-
86-
# Append data with interaction data
87-
data <- cbind(data, interaction_data)
88-
89-
# update measurement model with interaction constructs
90-
intxns_mm <- constructs(do.call("c", lapply(intxns_list, measure_interaction)))
91-
measurement_model <- rbind(measurement_model, intxns_mm)
92-
}
74+
post_interaction_object <- process_interactions(measurement_model, data, structural_model, inner_weights)
75+
measurement_model <- post_interaction_object$measurement_model
76+
data <- post_interaction_object$data
9377

9478
# warning if the model is incorrectly specified
95-
#warning_struc_meas_model_complete(structural_model,measurement_model,data)
79+
warnings(measurement_model, data, structural_model)
9680

9781
# Make a named list of construct measurement_mode functions
9882
measurement_mode_scheme <- sapply(unique(c(structural_model[,1], structural_model[,2])), get_measure_mode, measurement_model, USE.NAMES = TRUE)
9983

10084
# Run the model in simplePLS
10185
seminr_model = seminr::simplePLS(obsData = data, smMatrix = structural_model, mmMatrix = measurement_model, inner_weights = inner_weights, measurement_mode_scheme = measurement_mode_scheme)
10286
seminr_model$data <- data
103-
seminr_model$interactions <- interactions
10487
seminr_model$rawdata <- rawdata
10588
seminr_model$raw_measurement_model <- raw_measurement_model
10689

R/estimate_simplePLS.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#' simplePLS(obsData,smMatrix, mmMatrix,inner_weights = path_weighting,
2626
#' maxIt=300, stopCriterion=7,measurement_mode_scheme)
2727
#'
28-
#' @seealso \code{\link{relationships}} \code{\link{constructs}} \code{\link{paths}} \code{\link{interactions}}
28+
#' @seealso \code{\link{relationships}} \code{\link{constructs}} \code{\link{paths}} \code{\link{interaction_term}}
2929
#' \code{\link{estimate_pls}} \code{\link{bootstrap_model}}
3030
#'
3131
#' @examples

R/evaluate_effects.R

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#' @param dv A dependent variable in the model.
88
#'
99
#' @usage
10-
#' fsquared(model, iv, dv)
10+
#' fSquared(seminr_model, iv, dv)
1111
#'
1212
#' @references Cohen, J. (2013). Statistical power analysis for the behavioral sciences. Routledge.
1313
#'
@@ -40,15 +40,48 @@
4040
fSquared <- function(seminr_model, iv, dv) {
4141
with_sm <- seminr_model$smMatrix
4242
without_sm <- subset(with_sm, !((with_sm[, "source"] == iv) & (with_sm[, "target"] == dv)))
43-
capture.output(
43+
44+
# Calculate fSquared using LM of constructs instead of re-estiating the model (this is probably incorrect, but might serve for interaction models)
45+
# dvs <- unique(seminr_model$smMatrix[, "target"])
46+
# path_matrix <- seminr_model$path_coef
47+
# for (dv in dvs) {
48+
# ivs <- names(path_matrix[(path_matrix[,dv] != 0),dv])
49+
# sub("\\*", "x", ivs)
50+
# frmla <- stats::as.formula(paste(dv,paste(sub("\\*", "x", ivs), collapse ="+"), sep = " ~ "))
51+
# data <- as.data.frame(seminr_model$construct_scores)
52+
# colnames(data) <- sub("\\*", "x",colnames(data))
53+
# lm <- stats::lm(formula = frmla, data = data)
54+
# summary(lm)
55+
# }
56+
utils::capture.output(
4457
without_pls <- estimate_pls(data = seminr_model$rawdata,
45-
measurement_model = seminr_model$mmMatrix,
46-
interactions = seminr_model$interactions,
58+
measurement_model = seminr_model$raw_measurement_model,
4759
structural_model = without_sm)
4860
)
4961
with_r2 <- seminr_model$rSquared["Rsq", dv]
5062
ifelse(any(without_sm[,"target"] == dv),
5163
without_r2 <- without_pls$rSquared["Rsq", dv],
5264
without_r2 <- 0)
65+
5366
return((with_r2 - without_r2) / (1 - with_r2))
5467
}
68+
69+
model_fsquares <- function(seminr_model) {
70+
if (any(names(seminr_model$raw_measurement_model) == "orthogonal_interaction")
71+
| any(names(seminr_model$raw_measurement_model) == "two_stage_interaction")
72+
| any(names(seminr_model$raw_measurement_model) == "scaled_interaction" )) {
73+
return("The fSquare cannot be calculated as the model contains an interaction term and omitting either the antecedent or moderator in the interaction term will cause model estimation to fail")
74+
}
75+
path_matrix <- seminr_model$path_coef
76+
ivs <- unique(seminr_model$smMatrix[, "source"])
77+
dvs <- unique(seminr_model$smMatrix[, "target"])
78+
fsquared_matrix <- path_matrix
79+
for (dv in dvs) {
80+
for (iv in ivs) {
81+
fsquared_matrix[iv, dv] <- fSquared(seminr_model = seminr_model,
82+
iv = iv,
83+
dv = dv)
84+
}
85+
}
86+
return(fsquared_matrix)
87+
}

R/evaluate_reliability.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#' @usage
99
#' rho_A(seminr_model)
1010
#'
11-
#' @seealso \code{\link{relationships}} \code{\link{constructs}} \code{\link{paths}} \code{\link{interactions}}
11+
#' @seealso \code{\link{relationships}} \code{\link{constructs}} \code{\link{paths}} \code{\link{interaction_term}}
1212
#' \code{\link{bootstrap_model}}
1313
#'
1414
#' @references Dijkstra, T. K., & Henseler, J. (2015). Consistent partial least squares path modeling. MIS quarterly, 39(2).

R/evaluate_warnings.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,6 @@ warning_periods_in_col_names <- function(data) {
4747
warnings <- function(mmMatrix,data, smMatrix) {
4848
warning_single_item_formative(mmMatrix)
4949
warning_missing_data(data, mmMatrix)
50-
warning_periods_in_col_names(data)
50+
#warning_periods_in_col_names(data)
5151
}
5252

R/feature_consistent.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#' @usage
1010
#' PLSc(seminr_model)
1111
#'
12-
#' @seealso \code{\link{relationships}} \code{\link{constructs}} \code{\link{paths}} \code{\link{interactions}}
12+
#' @seealso \code{\link{relationships}} \code{\link{constructs}} \code{\link{paths}} \code{\link{interaction_term}}
1313
#' \code{\link{bootstrap_model}}
1414
#'
1515
#' @references Dijkstra, T. K., & Henseler, J. (2015). Consistent Partial Least Squares Path Modeling, 39(X).

R/feature_higher_order.R

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,68 @@
11
# Takes a HOC name and replaces that constructs relationships with the dimensions of the HOC
22
substitute_dimensions_for_HOC <- function(construct, sm, mm) {
33
# Identify dimensions of HOCs
4-
dimensions <- mm[mm[, "type"] == "HOCA" | mm[, "type"] == "HOCB", ][mm[mm[, "type"] == "HOCB" | mm[, "type"] == "HOCA", ][, "construct"] == construct, "measurement"]
4+
dimensions <- matrix(construct, ncol = 3, byrow = TRUE)[,2]
5+
#dimensions <- mm[mm[, "type"] == "HOCA" | mm[, "type"] == "HOCB", ][mm[mm[, "type"] == "HOCB" | mm[, "type"] == "HOCA", ][, "construct"] == construct, "measurement"]
56
# identify antecedent relationships to HOC
6-
antecedents <- sm[which(sm[, "target"] == construct), "source"]
7+
antecedents <- sm[which(sm[, "target"] == construct[1]), "source"]
78
# change antecedent relationship to first order constructs in structural model
89
if (!length(antecedents) == 0) {
910
sm <- rbind(sm,
1011
relationships(paths(from = antecedents,
1112
to = dimensions)))
12-
sm <- sm[-which(sm[, "target"] == construct), ]
13+
sm <- sm[-which(sm[, "target"] == construct[1]), ]
1314
}
1415

1516
# identify outcomes
16-
outcomes <- sm[which(sm[, "source"] == construct), "target"]
17+
outcomes <- sm[which(sm[, "source"] == construct[1]), "target"]
1718
if (!length(outcomes) == 0) {
1819
sm <- rbind(sm,
1920
relationships(paths(from = dimensions,
2021
to = outcomes)))
21-
sm <- sm[-which(sm[, "source"] == construct), ]
22+
sm <- sm[-which(sm[, "source"] == construct[1]), ]
2223
}
23-
return(sm)
24+
return(list(sm = sm,
25+
dimensions = dimensions))
2426
}
2527

2628
remove_HOC_in_measurement_model <- function(construct, mm) {
2729
mm[!mm[, "construct"] == construct, ]
2830
}
2931

3032
# Function to parse measurement and structural model and create the higher order model with complete information
31-
prepare_higher_order_model <- function(data, sm , mm, ints, inners) {
33+
prepare_higher_order_model <- function(data, sm , mm, inners, HOCs) {
3234
#retain the mm and sm
3335
orig_mm <- mm
36+
new_mm <- matrix(unlist(mm[!(substr(names(mm), nchar(names(mm))-10, nchar(names(mm))) == "interaction") & !(names(mm) == "higher_order_composite")]), ncol = 3, byrow = TRUE,
37+
dimnames = list(NULL, c("construct", "measurement", "type")))
3438
orig_sm <- sm
35-
# Identify HOCs
36-
HOCs <- unique(mm[which(mm[, "type"] == "HOCA" | mm[, "type"] == "HOCB"), "construct"])
37-
3839
# Rebuild model for first stage
3940
# Add new HOC paths to SM
41+
dimensions <- c()
4042
for (construct in HOCs) {
41-
sm <- substitute_dimensions_for_HOC(construct, sm, mm)
42-
#mm <- remove_HOC_in_measurement_model(construct,mm)
43+
obj <- substitute_dimensions_for_HOC(construct, sm, new_mm)
44+
sm <- obj$sm
45+
dimensions <- c(dimensions, obj$dimensions)
4346
}
47+
# Remove interactions from the sm
48+
sm <- sm[sm[, "source"] %in% unique(new_mm[, "construct"]),]
49+
50+
4451
# Identify all the dimensions
45-
dimensions <- orig_mm[which(orig_mm[, "construct"] == HOCs), "measurement"]
46-
# remove HOCs from mm
47-
new_mm <- mm[-which(mm[, "construct"] == HOCs), ]
52+
# dimensions <- orig_mm[which(orig_mm[, "construct"] == HOCs), "measurement"]
4853

4954
# Run first stage
5055
new_model <- estimate_pls(data = data,
51-
measurement_model = new_mm,
52-
interactions = ints,
56+
measurement_model = mm[!(substr(names(mm), nchar(names(mm))-10, nchar(names(mm))) == "interaction") & !(names(mm) == "higher_order_composite")],
5357
structural_model = sm,
5458
inner_weights = inners)
5559

5660
# Add the construct scores to data
5761
data <- cbind(data, new_model$construct_scores[, dimensions])
5862

59-
# Update the mm to include the type of the new data and item
60-
mm[mm[,"type"] == "HOCA", "type"] <- "A"
61-
mm[mm[,"type"] == "HOCB", "type"] <- "B"
63+
# # Update the mm to include the type of the new data and item
64+
# mm[mm[,"type"] == "HOCA", "type"] <- "A"
65+
# mm[mm[,"type"] == "HOCB", "type"] <- "B"
6266

6367

6468
# pass the updated mm, sm and data back to estimate_model()

0 commit comments

Comments
 (0)