Skip to content

Commit 5c80910

Browse files
Merge pull request #6 from AnthonyRaborn/devel
Version upgrade v0.4.3
2 parents ccc52f1 + d6d5e0f commit 5c80910

File tree

5 files changed

+83
-39
lines changed

5 files changed

+83
-39
lines changed

DESCRIPTION

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Package: ShortForm
22
Type: Package
33
Title: Automatic Short Form Creation
4-
Version: 0.4.2
5-
Date: 2018-10-16
4+
Version: 0.4.3
5+
Date: 2019-8-7
66
Authors@R: c(person("Anthony", "Raborn", email = "anthony.w.raborn@gmail.com", role = c("aut", "cre")), person("Walter", "Leite", email = "Walter.Leite@coe.ufl.edu", role = "aut"))
77
Description: Performs automatic creation of short forms of scales with an
88
ant colony optimization algorithm and a Tabu search. As implemented in the
@@ -19,7 +19,7 @@ Description: Performs automatic creation of short forms of scales with an
1919
<doi:10.1080/10705511.2017.1409074> for an applied example of the Tabu search.
2020
License: LGPL (>= 2.0, < 3) | Mozilla Public License
2121
LazyData: TRUE
22-
RoxygenNote: 6.1.0
22+
RoxygenNote: 6.1.1
2323
Suggests:
2424
knitr,
2525
MplusAutomation (>= 0.7),
@@ -35,4 +35,3 @@ Roxygen: list(wrap = FALSE)
3535
URL: https://github.com/AnthonyRaborn/ShortForm
3636
BugReports: https://github.com/AnthonyRaborn/ShortForm/issues
3737
Encoding: UTF-8
38-

R/ACO_lavaan.R

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,12 @@
101101
#' CFA. See \link[lavaan]{lavaan} for more details.
102102
#'@param pheromone.calculation A character string specifying the method for
103103
#' calculating the pheromone strength. Must be one of "\code{gamma}"
104-
#' (standardized regression coefficients) or "\code{variance}" (proportion of
105-
#' variance explained by model). You must specify the entire string.
104+
#' (standardized latent regression coefficients), "\code{beta}"
105+
#' (standardized observed regression coefficients), "\code{regression}"
106+
#' (both latent and observed regression coefficients, if they exist)
107+
#' or "\code{variance}" (proportion of
108+
#' variance explained by model). You must specify the entire string. Default is
109+
#' \code{gamma}.
106110
#'@param fit.indices The fit indices (in lavaan format) extracted for model
107111
#' optimization. See \link[lavaan]{lavaan} for more details.
108112
#'@param fit.statistics.test A character vector of the logical test being used
@@ -122,7 +126,7 @@
122126
#' run number, (b) the count number, (c) the ant number, (d) the step number
123127
#' (if the current run is successful) or "Failure" (if the current run is
124128
#' unsuccessful), and for successful runs (f) the chosen fit statistics (from
125-
#' \code{fit.indices}), the average of the gammas (standardized regression
129+
#' \code{fit.indices}), the average of the gammas and betas (standardized regression
126130
#' coefficients), and the overall variance explained of the current run.
127131
#'@param max.run The maximum number of ants to run before the algorithm stops.
128132
#' This includes failed iterations as well. Default is 1000.
@@ -133,11 +137,11 @@
133137
#' information for runs that do converge successfully. Default is \code{FALSE}.
134138
#'@return A list with four elements: the first containing a named matrix with
135139
#' final model's best fit indices, the final pheromone level (either the mean
136-
#' of the standardized regression coefficients (gammas), or the mean variance
140+
#' of the standardized regression coefficients (gammas, betas, or both), or the mean variance
137141
#' explained), and a series of 0/1 values indicating the items selected in the
138142
#' final solution, the second element containing tbe summary matrix of the
139143
#' best fit statistic value(s) for each run, the items chosen for said best fit,
140-
#' the mean gamma and variance explained for the best fit, and the item pheromone
144+
#' the mean gamma, beta, and variance explained for the best fit, and the item pheromone
141145
#' levels after each run, the third containing the best-fitting lavaan model
142146
#' object, and the fourth containing the best-fitting model syntax.
143147
#'
@@ -200,7 +204,7 @@
200204
antcolony.lavaan = function(data = NULL, sample.cov = NULL, sample.nobs = NULL,
201205
ants = 20, evaporation = 0.9, antModel, list.items = NULL,
202206
full = NULL, i.per.f = NULL, factors = NULL, bifactor = NULL, steps = 50,
203-
lavaan.model.specs = list(model.type = "cfa", auto.var = T, estimator = "default", ordered = NULL, int.ov.free = TRUE, int.lv.free = FALSE, auto.fix.first = TRUE, auto.fix.single = TRUE, auto.cov.lv.x = TRUE, auto.th = TRUE, auto.delta = TRUE, auto.cov.y = TRUE),
207+
lavaan.model.specs = list(model.type = "cfa", auto.var = T, estimator = "default", ordered = NULL, int.ov.free = TRUE, int.lv.free = FALSE, auto.fix.first = TRUE, auto.fix.single = TRUE, auto.cov.lv.x = TRUE, auto.th = TRUE, auto.delta = TRUE, auto.cov.y = TRUE, std.lv = F),
204208
pheromone.calculation = "gamma", fit.indices = c("cfi", "tli", "rmsea"),
205209
fit.statistics.test = "(cfi > 0.95)&(tli > 0.95)&(rmsea < 0.06)",
206210
summaryfile = NULL,
@@ -212,16 +216,16 @@ antcolony.lavaan = function(data = NULL, sample.cov = NULL, sample.nobs = NULL,
212216

213217
antcolony.lavaan.env <- new.env(parent = baseenv())
214218

215-
if(pheromone.calculation %in% c("gamma","variance") == FALSE) {
216-
stop("Pheromone calculation not recognized! Enter either \'gamma\' or \'variance\'." )
219+
if(pheromone.calculation %in% c("gamma", "beta", "regression", "variance") == FALSE) {
220+
stop("Pheromone calculation not recognized! Enter one of \'gamma\', \'beta\', \'regression\' or \'variance\'." )
217221
}
218222
# create initial, empty files to be used
219223
if(length(summaryfile) > 0){
220224
write(x = "", file = summaryfile)
221225
}
222226

223227
summary = matrix(nrow = 1,
224-
ncol = (full + 3 + 2 + length(fit.indices) + full))
228+
ncol = (full + 3 + 3 + length(fit.indices) + full))
225229
# ncol = number of items + 3 (run, ant, count) +
226230
# 2 (mean.gamma, mean.var.exp) + number of fit indices + number of items
227231

@@ -344,17 +348,19 @@ antcolony.lavaan = function(data = NULL, sample.cov = NULL, sample.nobs = NULL,
344348
model = new_ant_model, data = data, sample.cov = sample.cov,
345349
sample.nobs = sample.nobs,
346350
model.type = antcolony.lavaan.env$model.type,
347-
auto.var = antcolony.lavaan.env$auto.var,
348351
ordered = antcolony.lavaan.env$ordered,
349352
estimator = antcolony.lavaan.env$estimator,
350353
int.ov.free = antcolony.lavaan.env$int.ov.free,
351354
int.lv.free = antcolony.lavaan.env$int.lv.free,
352355
auto.fix.first = antcolony.lavaan.env$auto.fix.first,
356+
std.lv = antcolony.lavaan.env$std.lv,
353357
auto.fix.single = antcolony.lavaan.env$auto.fix.single,
358+
auto.var = antcolony.lavaan.env$auto.var,
354359
auto.cov.lv.x = antcolony.lavaan.env$auto.cov.lv.x,
355360
auto.th = antcolony.lavaan.env$auto.th,
356361
auto.delta = antcolony.lavaan.env$auto.delta,
357362
auto.cov.y = antcolony.lavaan.env$auto.cov.y))
363+
358364
# Save the error and warning messages
359365
warnings <- modelCheck[[2]]
360366
errors <- modelCheck[[3]]
@@ -365,7 +371,8 @@ antcolony.lavaan = function(data = NULL, sample.cov = NULL, sample.nobs = NULL,
365371
"WARNING: covariance matrix of latent variables is not positive definite",
366372
"WARNING: model has NOT converged",
367373
"WARNING: could not invert information matrix",
368-
"WARNING: the optimizer warns that a solution has NOT been found")
374+
"WARNING: the optimizer warns that a solution has NOT been found",
375+
"WARNING: some estimated ov variances are negative")
369376
bad.errors <- c("ERROR: initial model-implied matrix (Sigma) is not positive definite",
370377
"ERROR: missing observed variables in dataset")
371378
if(any(errors %in% bad.errors) || any(warnings %in% bad.warnings)){
@@ -391,23 +398,26 @@ antcolony.lavaan = function(data = NULL, sample.cov = NULL, sample.nobs = NULL,
391398
if (verbose == TRUE) {
392399
cat(" ")
393400
}
394-
# compute fit indices, gammas, and residual variances
401+
# compute fit indices, gammas, betas, and residual variances
395402
# first, fit indices
396403
model.fit <- lavaan::fitMeasures(modelCheck$lavaan.output, fit.indices)
397404

398-
# next, gamma/variances
405+
# next, gamma/beta/variances
399406
# estimate the standardized coefficients of the variables
400407
standard.coefs <- lavaan::standardizedSolution(modelCheck$lavaan.output, se = FALSE, zstat = FALSE, pvalue = FALSE, remove.def = TRUE)
401408
# extract the regression coefficients
402409
std.gammas <- standard.coefs[which(standard.coefs[,2]=="=~"),]$est.std
403-
410+
std.betas <- standard.coefs[which(standard.coefs[,2]=="~"),]$est.std
411+
std.reg.coef <- standard.coefs[which(standard.coefs[,2]=="~"|standard.coefs[,2]=="=~"),]$est.std
412+
404413
# obtains the variance explained ("rsquare") from lavaan
405414
variance.explained <- lavaan::lavInspect(modelCheck$lavaan.output, "rsquare")
406415
mapply(assign, names(model.fit), model.fit, MoreArgs=list(envir = antcolony.lavaan.env))
407416

408417
#saves information about the selected items and the RMSEA they generated for the final ant.
409418
if (ant == ants && length(summaryfile) > 0){
410-
fit.info = matrix(c(select.indicator,run,count,ant,model.fit,mean(std.gammas), mean(variance.explained),
419+
fit.info = matrix(c(select.indicator,run,count,ant,model.fit,mean(std.gammas), mean(std.betas),
420+
mean(variance.explained),
411421
round(include,2)),1,)
412422

413423
write.table(fit.info, file = summaryfile, append = T,
@@ -417,15 +427,16 @@ antcolony.lavaan = function(data = NULL, sample.cov = NULL, sample.nobs = NULL,
417427
if (ant == ants){
418428
summary <- rbind(summary,
419429
matrix(c(select.indicator,run,count,ant,model.fit,
420-
mean(std.gammas), mean(variance.explained),
430+
mean(std.gammas), mean(std.betas), mean(variance.explained),
421431
round(include,2)),1,))
422432
}
423433

424434
#provide feedback about search.
425435
if(length(feedbackfile) > 0){
426436
feedback = c(paste("<h1>","run:",run,"count:",count,"ant:",ant,"step:",step,"<br>",
427437
"Fit Statistics:",model.fit,"<br>",
428-
"GAMMA:",mean(std.gammas), "VAR.EXP:", mean(variance.explained),"</h1>" ) )
438+
"GAMMA:",mean(std.gammas), "BETA:",mean(std.betas),
439+
"VAR.EXP:", mean(variance.explained),"</h1>" ) )
429440
write(feedback, file = feedbackfile, append = T)
430441
}
431442

@@ -438,10 +449,17 @@ antcolony.lavaan = function(data = NULL, sample.cov = NULL, sample.nobs = NULL,
438449
if (pheromone.calculation == "gamma") {#mean of standardized gammas
439450
pheromone = round(mean(std.gammas, na.rm = T),3)
440451
} else {
452+
if (pheromone.calculation == "beta") { #mean of standardized betas
453+
pheromone = round(mean(std.betas, na.rm = T),3)
454+
} else {
455+
if (pheromone.calculation == "regression") { #mean of all regression coefs
456+
pheromone = round(mean(std.reg.coef, na.rm = T),3)
457+
}
441458
if (pheromone.calculation == "variance") { #mean of r^2 values
442459
pheromone = round(mean(variance.explained, na.rm = T),3)
443460
}
444461
}
462+
}
445463
}
446464

447465
#adjusts count based on outcomes and selects best solution.
@@ -533,10 +551,10 @@ antcolony.lavaan = function(data = NULL, sample.cov = NULL, sample.nobs = NULL,
533551
# dimnames(results) = list(c(item.vector),c("ratio","ranks"))
534552
#
535553
summary <- data.frame(summary[-1,])
536-
colnames(summary) = c(item.vector, "run", "ant", "count", fit.indices, "mean.gamma", "mean.var.exp", paste0(item.vector, ".Pheromone"))
554+
colnames(summary) = c(item.vector, "run", "ant", "count", fit.indices, "mean.gamma", "mean.beta", "mean.var.exp", paste0(item.vector, ".Pheromone"))
537555

538556
final.solution = matrix(c(best.so.far.fit.indices,best.so.far.pheromone,best.so.far.solution),1,,
539-
dimnames=list(NULL,c(names(model.fit),"mean_gamma",item.vector)))
557+
dimnames=list(NULL,c(names(model.fit),paste0("mean_", pheromone.calculation), item.vector)))
540558
results = list(final.solution, summary, 'best.model' = best.so.far.model, 'best.syntax' = best.so.far.syntax)
541559
class(results) = "antcolony"
542560
#FINISH FUNCTION.

R/shortform_plots.R

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77
#' Objects of classes \code{tabu} and \code{simulatedAnnealing} produce a
88
#' single plot which show the changes in the objective function across each
99
#' iteration of the algorithm. Objects of class \code{antcolony} can produce
10-
#' up to three plots which show the changes in the pheromone levels for each
10+
#' up to four plots which show the changes in the pheromone levels for each
1111
#' item, changes in the average standardized regression coefficients of the
12-
#' model, and changes in the amount of variance explained in the model across
13-
#' each iteration of the algorithm.
12+
#' model (gammas and betas), and changes in the amount of variance explained
13+
#' in the model across each iteration of the algorithm.
1414
#'
1515
#' These functions do not currently allow users to modify the resulting
1616
#' plots directly, but the objects produces are \pkg{ggplot2} objects which
1717
#' should allow for additional user customization.
1818
#'
1919
#' @param x An object with one of the following classes: \code{antcolony},
2020
#' \code{tabu}, or \code{simulatedAnnealing}.
21-
#' @param type A character string. One of "all", "pheromone", "gamma", or
21+
#' @param type A character string. One of "all", "pheromone", "gamma", "beta", or
2222
#' "variance". Matched literally. Only used with objects of class \code{antcolony}.
2323
#' @param ... Not used with the current S3 method implementation.
2424
#' @name plot
@@ -27,7 +27,7 @@
2727

2828
plot.antcolony <- function(x, type = "all", ...) {
2929
summary_results <- x[[2]]
30-
pheromone_plot = gamma_plot = variance_plot = NULL
30+
pheromone_plot = gamma_plot = beta_plot = variance_plot = NULL
3131
item_pheromone_names <-
3232
grep("Pheromone", names(summary_results), value = TRUE)
3333

@@ -87,6 +87,28 @@ plot.antcolony <- function(x, type = "all", ...) {
8787
)
8888
}
8989

90+
if (type %in% c("all", "beta")) {
91+
beta_plot <-
92+
ggplot2::ggplot(summary_results,
93+
ggplot2::aes_string(x = "run", y = "mean.beta")) +
94+
ggplot2::geom_smooth(fullrange = TRUE, se = FALSE, na.rm = T) +
95+
ggplot2::ylab(expression("Mean " * beta)) +
96+
ggplot2::ggtitle(expression("Smoothed Changes in Mean " * beta)) +
97+
ggplot2::geom_text(ggplot2::aes(label = ifelse(
98+
summary_results$run %in% c(1, max(summary_results$run)),
99+
round(summary_results$mean.beta, 3), ""
100+
)), vjust = 0, na.rm = T) +
101+
ggplot2::theme_bw() +
102+
ggplot2::theme(
103+
legend.position = "none",
104+
plot.title = ggplot2::element_text(
105+
size = 23,
106+
face = "bold",
107+
hjust = .5
108+
)
109+
)
110+
}
111+
90112
if (type %in% c("all", "variance")) {
91113
variance_plot <-
92114
ggplot2::ggplot(summary_results,
@@ -109,7 +131,8 @@ plot.antcolony <- function(x, type = "all", ...) {
109131
)
110132
}
111133

112-
plots <- list("Pheromone" = pheromone_plot, "Gamma" = gamma_plot, "Variance" = variance_plot)
134+
plots <- list("Pheromone" = pheromone_plot, "Gamma" = gamma_plot,
135+
"Beta" = beta_plot, "Variance" = variance_plot)
113136
return(plots)
114137

115138
}

man/antcolony.lavaan.Rd

Lines changed: 10 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/plot.Rd

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)