├── .DS_Store ├── .Rbuildignore ├── .gitignore ├── DESCRIPTION ├── LCTMtools.Rproj ├── LCTMtools.pdf ├── LCTMtoolsvignette.pdf ├── NAMESPACE ├── R ├── .DS_Store ├── LCTMcompare.R ├── LCTMtoolkit.R ├── LCTMtools.R ├── actual_proportions.R ├── appa.R ├── bmi.R ├── bmi_long.R ├── class_assignment.R ├── confusion_matrix.R ├── entropy.R ├── gg_color_hue.R ├── kappa_matrix.R ├── mismatch.R ├── mmlcr_to_lctm.R ├── occ.R ├── plotLCTM.R ├── relative_entropy.R ├── residualplot_step1.R └── sastraj_to_lctm.R ├── README.md ├── data ├── .DS_Store ├── bmi.rda └── bmi_long.rda ├── inst └── .DS_Store ├── man ├── .DS_Store ├── LCTMcompare.Rd ├── LCTMtoolkit.Rd ├── LCTMtools.Rd ├── actual_proportions.Rd ├── appa.Rd ├── bmi.Rd ├── bmi_long.Rd ├── class_assignment.Rd ├── confusion_matrix.Rd ├── entropy.Rd ├── gg_color_hue.Rd ├── kappa_matrix.Rd ├── mismatch.Rd ├── mmlcr_to_lctm.Rd ├── occ.Rd ├── plotLCTM.Rd ├── relative_entropy.Rd ├── residualplot_step1.Rd └── sastraj_to_lctm.Rd └── vignettes ├── .DS_Store ├── .gitignore ├── Mod_A_SAS.png ├── Mod_C_SAS.png ├── Mod_D_SAS.png ├── Mod_G_SAS.png ├── figures ├── Mod_A_SAS.png ├── Mod_C_SAS.png ├── Mod_D_SAS.png └── Mod_G_SAS.png ├── lctmtools-vignette.Rmd ├── lctmtools-vignette_cache └── html │ ├── __packages │ ├── ks_b172c03810a3605c9042f7aeedb55b3d.rdb │ ├── ks_b172c03810a3605c9042f7aeedb55b3d.rdx │ ├── lctm_8fc028651e91f9a2dc024e5ee476be43.RData │ ├── lctm_8fc028651e91f9a2dc024e5ee476be43.rdb │ ├── mode_365034ed67070d5e4a67d070f837a384.RData │ ├── mode_365034ed67070d5e4a67d070f837a384.rdb │ ├── mode_365034ed67070d5e4a67d070f837a384.rdx │ ├── model1_66a716ae3e03f0eac2b3bc1f6ec01690.RData │ ├── modf_003c84d0db12ab3e4db589af135952b2.rdb │ ├── modf_003c84d0db12ab3e4db589af135952b2.rdx │ ├── plotpred_2b9228e8e187dade2d8457efa857f260.rdb │ ├── plotpred_2b9228e8e187dade2d8457efa857f260.rdx │ ├── pprob_62a1a4906f1c2035e60addcb2764c199.rdb │ ├── pprob_62a1a4906f1c2035e60addcb2764c199.rdx │ ├── pprob_ee61d6d999d6bf13cf513ed80f439002.RData │ ├── pprob_ee61d6d999d6bf13cf513ed80f439002.rdb │ ├── wm_7d81148f029fa3f335a866d7a95b100c.RData │ ├── wm_7d81148f029fa3f335a866d7a95b100c.rdb │ └── wm_7d81148f029fa3f335a866d7a95b100c.rdx └── rsconnect └── documents └── lctmtools-vignette.Rmd └── rpubs.com └── rpubs └── Document.dcf /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/.DS_Store -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^packrat/ 4 | ^\.Rprofile$ 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | inst/doc 2 | .Rproj.user 3 | .Rhistory 4 | .RData 5 | .Ruserdata 6 | packrat/lib*/ 7 | p2.png 8 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: LCTMtools 2 | Type: Package 3 | Title: Latent Class Trajectory Models: Tools for checking adequacy 4 | Version: 0.1.3 5 | Authors@R: person("Hannah", "Lennon", email = "hannah.lennon.manchester@gmail.com", 6 | role = c("aut", "cre")) 7 | URL: http://www.hannahlennon.com 8 | BugReports: https://github.com/hlennon/LCTMtools/issues 9 | Description: A selection of model adequacy tests for Latent Class Trajectory Models (LCTMs) 10 | which include the APPA (average posterior probability of assignment), the OCC (odds of correct classification), entropy and relative entropy. 11 | See the github.com/hlennon/LCTMtools for more information, documentation and examples. 12 | License: GPL-3 13 | Encoding: UTF-8 14 | LazyData: true 15 | RoxygenNote: 6.1.1 16 | Depends: R (>= 2.10) 17 | Imports: 18 | stats, 19 | psych, 20 | lcmm, 21 | ggplot2, 22 | dplyr 23 | Suggests: 24 | knitr, 25 | rmarkdown 26 | VignetteBuilder: knitr 27 | -------------------------------------------------------------------------------- /LCTMtools.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 20 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /LCTMtools.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/LCTMtools.pdf -------------------------------------------------------------------------------- /LCTMtoolsvignette.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/LCTMtoolsvignette.pdf -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(LCTMcompare) 4 | export(LCTMtoolkit) 5 | export(actual_proportions) 6 | export(appa) 7 | export(class_assignment) 8 | export(confusion_matrix) 9 | export(entropy) 10 | export(gg_color_hue) 11 | export(kappa_matrix) 12 | export(mismatch) 13 | export(mmlcr_to_lctm) 14 | export(occ) 15 | export(plotLCTM) 16 | export(relative_entropy) 17 | export(residualplot_step1) 18 | export(sastraj_to_lctm) 19 | importFrom(grDevices,hcl) 20 | -------------------------------------------------------------------------------- /R/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/R/.DS_Store -------------------------------------------------------------------------------- /R/LCTMcompare.R: -------------------------------------------------------------------------------- 1 | #' A model comparison toolkit. 2 | #' \code{LCTMcompare} 3 | #' 4 | #' The function LCTMcompare gives a summary of comparison between fitted LCTM models. 5 | #' 6 | #' @param modelA is the output from hlme() R model or model is the output of SASmodelbuilder(oe, os, op, of) passed through it 7 | #' @param modelB the model to be compared which is the output from hlme() R model or model is the output of SASmodelbuilder(oe, os, op, of) passed through it 8 | #' @return A selection of model adequacy tests, including the APPA (average posterior probability of assignment), the OCC (odds of correct classification), entropy $E$, Relative entropy ($E_k$), 9 | #' @references \url{https://bmjopen.bmj.com/content/8/7/e020683} 10 | #' @examples 11 | #' data(bmi_long, package='LCTMtools') 12 | #' require(lcmm) 13 | #' set.seed(999) 14 | #' data(bmi_long, package = 'LCTMtools' ) 15 | #' # Use the hlme function from the 'lcmm' R package to fit a 2 class latent class trajectory model 16 | #' model2classes <- lcmm::hlme(fixed = bmi ~ age + I(age^2), 17 | #' mixture= ~ age, 18 | #' random = ~ age, 19 | #' ng = 2, 20 | #' nwg = TRUE, 21 | #' subject = "id", 22 | #' data = data.frame(bmi_long[1:500, ] )) 23 | #' # Compute model adequacy measures 24 | #' LCTMtoolkit(model2classes) 25 | #' # Compare with a 3 class model 26 | #' model3classes <- lcmm::hlme(fixed = bmi ~ age + I(age^2), 27 | #' mixture= ~ age, 28 | #' random = ~ age, 29 | #' ng = 3, 30 | #' nwg = TRUE, 31 | #' subject = "id", 32 | #' data = data.frame(bmi_long[1:500, ] )) 33 | #' LCTMtoolkit(model3classes) 34 | #' LCTMcompare(model2classes, model3classes) 35 | #' @export 36 | 37 | LCTMcompare <- function(modelA, modelB) { 38 | 39 | 40 | model <- modelA 41 | n <- nrow(model$pprob) 42 | K <- ncol(model$pprob) - 2 43 | p <- model$pprob[, c(paste0("prob", 1:K, sep = ""))] 44 | 45 | 46 | if (class(model$call) == "SAS") { 47 | PI <- os$PI/100 48 | } else { 49 | PI <- exp(c(model$best[1:(K - 1)], 0))/(sum(exp(c(model$best[1:(K - 1)], 50 | 0)))) 51 | } 52 | 53 | 54 | 55 | output1 <- t(data.frame(Entropy = entropy(p), Relative_entropy = relative_entropy(p), 56 | BIC = model$BIC, AIC = model$AIC)) 57 | 58 | 59 | 60 | model <- modelB 61 | n <- nrow(model$pprob) 62 | K <- ncol(model$pprob) - 2 63 | p <- model$pprob[, c(paste0("prob", 1:K, sep = ""))] 64 | 65 | 66 | if (class(model$call) == "SAS") { 67 | PI <- os$PI/100 68 | } else { 69 | PI <- exp(c(model$best[1:(K - 1)], 0))/(sum(exp(c(model$best[1:(K - 1)], 70 | 0)))) 71 | } 72 | 73 | output2 <- t(data.frame(Entropy = entropy(p), Relative_entropy = relative_entropy(p), 74 | BIC = model$BIC, AIC = model$AIC)) 75 | 76 | output1 <- round(output1, 3) 77 | output2 <- round(output2, 3) 78 | Recommendation <- c("Close to zero", "Close to 1", "-", "-") 79 | output <- data.frame(output1, output2, Recommendation) 80 | 81 | return(output) 82 | } 83 | -------------------------------------------------------------------------------- /R/LCTMtoolkit.R: -------------------------------------------------------------------------------- 1 | #' A toolkit which computes a selection of model adequacy tests 2 | #' \code{LCTMtoolkit} 3 | #' 4 | #' The function LCTMtoolkit computes a selection of model adequacy tests, including the APPA (average posterior probability of assignment), the OCC (odds of correct classification), entropy E, Relative entropy (E_k), odds of correct classification is the ratio of the odds of classification based on the maximum posterior probablity classification rule and the estimated class membership proportions (pi_k) 5 | #' 6 | #' @param model the models to be compared which is the output from hlme() R model or model is the output of SASmodelbuilder(oe, os, op, of) passed through it 7 | #' @return A selection of model adequacy tests, including the APPA (average posterior probability of assignment), the OCC (odds of correct classification), entropy $E$, Relative entropy ($E_k$), 8 | #' @references \url{https://bmjopen.bmj.com/content/8/7/e020683} 9 | #' @examples 10 | #' data(bmi_long, package='LCTMtools') 11 | #' require(lcmm) 12 | #' model2class <- lcmm::hlme(fixed = bmi ~ age, 13 | #' mixture= ~ age, 14 | #' random= ~ age, 15 | #' nwg=TRUE, ng=2, subject="id", 16 | #' data=data.frame(bmi_long[1:500, ])) 17 | #' postprob(model2class) 18 | #' LCTMtoolkit(model2class) 19 | #' @export 20 | 21 | LCTMtoolkit <- function(model) { 22 | 23 | if(!(class(model)!="hlme"| 24 | class(model)!="SAS") | 25 | class(model)!="lcmm") print("class(model) type required to be hlme, lcmm or an imported PROC TRAJ object from SAS"); 26 | n <- nrow(model$pprob) 27 | K <- ncol(model$pprob) - 2 28 | p <- model$pprob[, c(paste0("prob", 1:K, sep = ""))] 29 | 30 | 31 | if (class(model$call) == "SAS") { 32 | PI <- os$PI/100 33 | } else { 34 | PI <- exp(c(model$best[1:(K - 1)], 0))/(sum(exp(c(model$best[1:(K - 1)], 35 | 0)))) 36 | } 37 | 38 | 39 | outputs <- matrix(0, nrow = 3, ncol = K) 40 | colnames(outputs) <- paste0("Class_", 1:K, sep = "") 41 | rownames(outputs) <- c("APPA", "OCC", "Mismatch") 42 | outputs[1, ] <- appa(p) 43 | outputs[2, ] <- occ(p, PI) 44 | outputs[3, ] <- mismatch(p, PI) 45 | Recommendation <- c("Greater than 0.7", "Greater than 5", "Close to zero") 46 | outputs <- data.frame(round(outputs, 3), Recommendation) 47 | 48 | ep <- entropy(p) 49 | rep <- relative_entropy(p) 50 | outputs1 <- t(data.frame(Entropy = ep, 51 | Relative_entropy = rep, 52 | BIC = model$BIC, 53 | AIC = model$AIC)) 54 | Recommendation <- c("Close to zero", "Close to 1", "-", "-") 55 | outputs1 <- round(outputs1, 3) 56 | outputs1 <- data.frame(Model = outputs1, Recommendation = Recommendation) 57 | 58 | outputs2 <- list(outputs, outputs1) 59 | names(outputs2) <- c("Class-specific", "Model-specific") 60 | 61 | print(outputs2) 62 | 63 | outputs3 <- list(appa=outputs[1,1:K], 64 | occ=outputs[2,1:K], 65 | mismatch=outputs[3,1:K], 66 | entropy=ep, 67 | relativeentropy=rep, 68 | BIC=model$BIC, 69 | AIC=model$AIC 70 | ) 71 | return(outputs3) 72 | } 73 | -------------------------------------------------------------------------------- /R/LCTMtools.R: -------------------------------------------------------------------------------- 1 | #' LCTMtools: A package for computing a number of Latent Class Trajectory Model tools for a given hlme() object or SAS model. 2 | #' 3 | #' The LCTMtools package provides two categories of important functions: 4 | #' LCTMtools (to test a models adequacy) and LCTMcompare (to aid model selection). 5 | #' 6 | #' @section LCTMtools functions: 7 | #' The LCTMtools functions arw a selection of model adequacy tests for Latent Class Trajectory Models (LCTMs) which include the APPA (average posterior probability of assignment), the OCC (odds of correct classification), entropy, Relative entropy. 8 | #' 9 | #' @docType package 10 | #' @name LCTMtools 11 | NULL 12 | -------------------------------------------------------------------------------- /R/actual_proportions.R: -------------------------------------------------------------------------------- 1 | #' The proportion within each class 2 | #' 3 | #' \code{actual_proportions} 4 | #' The proportion within each class AFTER class assignment (using max posterior rule) 5 | #' 6 | #' @param p is the posterior probabilities of assignment of dimensions, K columns and N rows 7 | #' @return The proportion within each class AFTER class assignment (using max posterior rule) 8 | #' @examples 9 | #' \dontrun{actual_proportions(p)} 10 | #' @export 11 | 12 | actual_proportions <- function(p) { 13 | K <- ncol(p) 14 | 15 | # determine class 16 | group <- class_assignment(p) 17 | 18 | # Tabulate the actual proportions 19 | actprop <- tabulate(group, nbins = K)/nrow(p) 20 | 21 | # return the proportion of individuals assignes using the max post prob rule 22 | return(actprop) 23 | } 24 | -------------------------------------------------------------------------------- /R/appa.R: -------------------------------------------------------------------------------- 1 | #' The Average Posterior Probability Assignment (APPA) 2 | #' 3 | #' \code{appa} 4 | #' 5 | #' Computes the Average Posterior Probability Assignment (APPA) for a K latent class trajectory model. 6 | #' 7 | #' @param p is the posterior probabilities of assignment of dimensions, K columns and N rows 8 | #' @return The Average Posterior Probability Assignment (APPA) for each class 9 | #' @examples 10 | #' \dontrun{appa(p)} 11 | #' @export 12 | 13 | appa <- function(p) { 14 | # determine class size 15 | K <- ncol(p) 16 | 17 | # determine class 18 | group <- class_assignment(p) 19 | 20 | # save vector for appa values 21 | app <- rep(NA, times = K) 22 | 23 | # Compute average posterior probabilites 24 | for (i in 1:K) { 25 | classp <- p[group == i, i] 26 | if (length(classp) != 0) 27 | app[i] <- mean(classp) 28 | } 29 | return(app) 30 | } 31 | -------------------------------------------------------------------------------- /R/bmi.R: -------------------------------------------------------------------------------- 1 | #' Body Mass Index (BMI) repeated measures of 10,000 individuals in wide format. 2 | #' 3 | #' A wide format data frame of simulated BMI values of 10,000 individuals. 4 | #' 5 | #' 6 | #' @format A wide format data frame of simulated BMI values of 10,000 individuals. 7 | #' \describe{ 8 | #' \item{id}{Individual ID} 9 | #' \item{bmi}{Body mass index of the individual at times T1,T2, T3 and T4, in kg/m^2} 10 | #' \item{T}{Time of BMI measure, in years} 11 | #' \item{true_class}{Tag to identify the class the individual BMI data was simulated from} 12 | #' } 13 | 14 | "bmi" 15 | -------------------------------------------------------------------------------- /R/bmi_long.R: -------------------------------------------------------------------------------- 1 | #' Body Mass Index (BMI) repeated measures of 10,000 individuals in long format. 2 | #' 3 | #' A long format data frame of simulated BMI values of 10,000 individuals. 4 | #' 5 | #' 6 | #' @format A long format data frame of simulated BMI values of 10,000 individuals. 7 | 8 | #' \describe{ 9 | #' \item{id}{Individual ID} 10 | #' \item{age}{Age of BMI measure, in years} 11 | #' \item{bmi}{Body mass index of the individual at times T1,T2, T3 and T4, in kg/m^2} 12 | #' \item{true_class}{Tag to identify the class the individual BMI data was simulated from} 13 | #' } 14 | 15 | "bmi_long" 16 | -------------------------------------------------------------------------------- /R/class_assignment.R: -------------------------------------------------------------------------------- 1 | #' Maximum class assignment 2 | #' \code{class_assignment} 3 | #' Maximum class assignment 4 | #' @param p is the posterior probabilities of assignment of dimensions, K columns and N rows 5 | #' @return This function computes the Average Posterior Probability Assignment (APPA) for a K latent class trajectory model. 6 | #' @examples 7 | #' \dontrun{class_assignment(p)} 8 | #' @export 9 | 10 | class_assignment <- function(p) { 11 | return(as.numeric(apply(p, 1, which.max))) 12 | } 13 | -------------------------------------------------------------------------------- /R/confusion_matrix.R: -------------------------------------------------------------------------------- 1 | #' A confusion matrix 2 | #' 3 | #' 4 | #' A matrix, also known as a matching matrix or an error matrix, is a specific table layout that allows visualization of the performance of an algorithm, typically a supervised learning one. Each row of the matrix represents the instances in a predicted class for model 1 while each column represents the instances in class for model 2. The name stems from the fact that it makes it easy to see if the system is confusing two classes (i.e. commonly mislabeling one as another). 5 | #' 6 | #' @usage confusion_matrix(model1, model2, "ModelA", "ModelB") 7 | #' @param model1 A fitted model from the lcmm R package (or from SAS passed through the SASmodelbuilder() function) 8 | #' @param model2 is the posterior probabilities of assignment of dimensions, K columns and N rows 9 | #' @param name1 optional paramter to pre-specify name of model 10 | #' @param name2 optional paramter to pre-specify name of model 11 | #' @return A confusion matrix between two models with the same number of classes 12 | #' @examples 13 | #' \dontrun{ 14 | #' data(bmi_long, package='LCTMtools') 15 | #' library(lcmm) 16 | #' model1 <- lcmm::hlme(BMI ~Age, 17 | #' mixture= ~Age, 18 | #' random= ~Age, 19 | #' nwg=TRUE, ng=2, subject='ID', data=data.frame(bmi_long[1:500, ])) 20 | #' model2 <- lcmm::hlme(BMI ~Age, 21 | #' mixture= ~Age, 22 | #' random= ~1, 23 | #' nwg=FALSE, ng=2, subject='ID', data=data.frame(bmi_long[1:500, ])) 24 | #' confusion_matrix(model1, model2)} 25 | #' @export 26 | 27 | confusion_matrix <- function(model1, model2, name1 = "Model_1", name2 = "Model_2") { 28 | # model1 <- model1[sort(model1$ID),] 29 | R <- model1$pprob$class 30 | Sas <- model2$pprob$class 31 | K <- ncol(model1$pprob) - 2 32 | 33 | 34 | a <- eval(parse(text = paste0("c(", paste0("sum(R==1&Sas==", 1:K, ")", collapse = ","), 35 | ")"))) 36 | 37 | for (i in 2:K) { 38 | b <- eval(parse(text = paste0("c(", paste0("sum(R==", i, "&Sas==", 1:K, 39 | ")", collapse = ","), ")"))) 40 | a <- rbind(a, b) 41 | } 42 | 43 | a <- cbind(a, rowSums(a)) 44 | a <- rbind(a, colSums(a)) 45 | colnames(a) <- c(paste0("Class_", 1:K), name1) 46 | rownames(a) <- c(paste0("Class_", 1:K), name2) 47 | return(a) 48 | } 49 | -------------------------------------------------------------------------------- /R/entropy.R: -------------------------------------------------------------------------------- 1 | #' Entropy 2 | #' 3 | #' A global measure of uncertainty with values close to zero implying a good model. Entropy is a global measure of classification uncertainty, which takes into account all N × K posterior probabilities. The entropy of a model is defined as which takes values from [0,infinity), with higher values indicating a larger amount of uncertainty. Entropy values closest to 0 correspond to models with least classification uncertainty. 4 | #' 5 | #' @param p is the posterior probabilities of assignment of dimensions, K columns and N rows 6 | #' @return Entropy value between (0, infinity) 7 | #' @examples 8 | #' \dontrun{entropy(p)} 9 | #' @export 10 | 11 | entropy <- function(p) { 12 | ent <- -1 * sum(p * log(p), na.rm = TRUE) 13 | 14 | return(ent) 15 | } 16 | -------------------------------------------------------------------------------- /R/gg_color_hue.R: -------------------------------------------------------------------------------- 1 | #' gg_color_hue 2 | #' 3 | #' Emulate ggplot2 default colour palette 4 | #' 5 | #' @param n Number of coloures 6 | #' @return a vector of n colour codes 7 | #' @references https://www.rdocumentation.org/packages/iprior/versions/0.7.1/topics/gg_colour_hue 8 | #' @examples 9 | #' gg_color_hue(2) 10 | #' gg_color_hue(4) 11 | #' plot(1:10, pch=12, col=gg_color_hue(10), lwd=30, xaxt="n", yaxt="n", ylab="", xlab="") 12 | #' @export 13 | #' 14 | gg_color_hue <- function(n) { 15 | hues = seq(15, 375, length = n + 1) 16 | hcl(h = hues, l = 65, c = 100)[1:n] 17 | } 18 | -------------------------------------------------------------------------------- /R/kappa_matrix.R: -------------------------------------------------------------------------------- 1 | #' Kappa matrix 2 | #' 3 | #' Kappa matrix of cohen's kappa values 4 | #' 5 | #' @param ConfMatrix A confusion matrix made using confusion_matrix(model1, model2) 6 | #' @param acc The accuracy of the results, defaults to 2 decimal places 7 | #' @return Unweighted and weighted Kappa value computed using the cohen.kappa() function from the psych R package 8 | #' @examples 9 | #' data(bmi_long, package='LCTMtools') 10 | #' require(lcmm) 11 | #' require(psych) 12 | #' model1 <- hlme(fixed = bmi ~ age, 13 | #' mixture= ~ age, 14 | #' random= ~ age, 15 | #' nwg=TRUE, ng=2, subject="id", data=data.frame(bmi_long[1:500, ])) 16 | #' 17 | #' model2 <- hlme(fixed = ~ age, 18 | #' mixture= ~ age, 19 | #' random= ~1, nwg=FALSE, ng=2, subject="id", data=data.frame(bmi_long[1:500, ])) 20 | #' ConfMatrix <- confusion_matrix(model1, model2) 21 | #' kappa_matrix(ConfMatrix) 22 | #' @export 23 | 24 | kappa_matrix <- function(ConfMatrix, acc = 2) { 25 | K <- nrow(ConfMatrix) - 1 26 | x <- psych::cohen.kappa(ConfMatrix[1:K, 1:K]) 27 | mxu <- round(x$kappa, acc) 28 | lou <- round(x$confid[1, 1], acc) 29 | upu <- round(x$confid[1, 3], acc) 30 | mxw <- round(x$weighted.kappa, acc) 31 | low <- round(x$confid[2, 1], acc) 32 | upw <- round(x$confid[2, 3], acc) 33 | unw <- c(paste0("Kappa Values: (unweighted) ", mxu, " (", lou, ", ", upu, 34 | ") ")) 35 | w <- c(paste0("Kappa Values: (weighted) ", mxw, " (", low, ", ", upw, ") ")) 36 | 37 | return(list(unweighted_kappa = unw, weighted_kappa = w)) 38 | } 39 | -------------------------------------------------------------------------------- /R/mismatch.R: -------------------------------------------------------------------------------- 1 | #' Computes the mismatch of the posterior probabilities (mismatch=actual-estimated) 2 | #' 3 | #' @param p is the posterior probabilities of assignment of dimensions, K columns and N rows 4 | #' @param pi is the estimated proportion of class membership of length K 5 | #' @return The mismatch of posterior probabilities 6 | #' @examples 7 | #' \dontrun{mismatch(p, pi)} 8 | #' @export 9 | 10 | mismatch <- function(p, pi) { 11 | # determine class 12 | group <- class_assignment(p) 13 | K <- ncol(p) 14 | 15 | # Tabulate the actual proportions 16 | actprop <- tabulate(group, nbins = K)/nrow(p) 17 | 18 | # Compute the mismatch (mismatch=actual-estimated) 19 | return(actprop - pi) 20 | } 21 | -------------------------------------------------------------------------------- /R/mmlcr_to_lctm.R: -------------------------------------------------------------------------------- 1 | #' Converts an R mmclr model output to the format of R's hlme class 2 | #' 3 | #' @param model contains model parameter estimates and maximised likelihood, AIC, BIC values 4 | #' @return A format to feed into the LCTMtoolkit() R function 5 | #' @examples 6 | #' \dontrun{mmlcr_to_lctm(model)} 7 | #' @export 8 | 9 | mmlcr_to_lctm <- function(model) { 10 | mod <- list(NULL) 11 | n <- length(unique(model$components[[1]]$data$ident)) 12 | K <- ncol(model$post.prob) - 1 13 | 14 | mod$pprob <- as.data.frame(model$post.prob[, c("groupe", paste0("PostProb", 15 | 1:K, sep = ""))]) 16 | mod$pprob <- data.frame(ID = row.names(model$post.prob), mod$pprob) 17 | colnames(mod$pprob) <- c("ID", "class", paste0("prob", 1:K, sep = "")) 18 | 19 | mod$call <- "Rmmlcr" 20 | mod$par <- exp(model$gamma.matrix)/(sum(exp(c(model$gamma.matrix)))) 21 | mod$n <- n 22 | mod$K <- K 23 | mod$logLik <- model$loglikelihood 24 | mod$BIC <- model$BIC 25 | mod$AIC <- model$AIC 26 | mod$best <- unlist(model$components[[1]]$coef) 27 | 28 | return(mod) 29 | } 30 | # os$PI/100 exp(c(M$best[1:4], 0))/(sum(exp(c(M$best[1:4], 0)))) 31 | -------------------------------------------------------------------------------- /R/occ.R: -------------------------------------------------------------------------------- 1 | #' The odds of correct classification is the ratio of the odds of classification based on the maximum posterior probablity classification rule and the estimated class membership proportions (pi_k). 2 | #' 3 | #' @param p is the posterior probabilities of assignment of dimensions, K columns and N rows 4 | #' @param pi is the estimated proportion of class membership of length K 5 | #' @return The odds of correct classification 6 | #' @examples 7 | #' \dontrun{occ(p, pi)} 8 | #' @export 9 | 10 | occ <- function(p, pi) { 11 | app <- appa(p) 12 | numerator <- app/(1 - app) 13 | denominator <- pi/(1 - pi) 14 | occ <- numerator/denominator 15 | return(occ) 16 | } 17 | -------------------------------------------------------------------------------- /R/plotLCTM.R: -------------------------------------------------------------------------------- 1 | #' plotLCTM 2 | #' 3 | #' A wrapper funciton to plot hlme trajectories in ggplot2 style. 4 | #' This does the same fuction as predictY in the lcmm package. 5 | #' 6 | #' @param m fitted hlme or lcmm model using the lcmm R package 7 | #' @return A plot in ggplot style 8 | #' @importFrom grDevices hcl 9 | #' @examples 10 | #' library(ggplot2) 11 | #' data(bmi_long, package='LCTMtools') 12 | #' require(lcmm) 13 | #' model2class <- lcmm::hlme(fixed = bmi ~ age, 14 | #' mixture= ~ age, 15 | #' random= ~ age, 16 | #' nwg=TRUE, ng=2, subject="id", 17 | #' data=data.frame(bmi_long[1:500, ])) 18 | #' plotLCTM(model2class, shape="linear") 19 | #' 20 | #' library(splines) # For use of natural splines 21 | #' model2class_splines <- lcmm::hlme(fixed = bmi ~ ns(age, knots=2), 22 | #' mixture= ~ ns(age, knots=2), 23 | #' random= ~ age, 24 | #' nwg=TRUE, ng=2, subject="id", 25 | #' data=data.frame(bmi_long[1:500, ])) 26 | #' newdat <- data.frame(age=seq(0, 4.7, length=100)) 27 | #' #plotLCTM(model2class_splines, shape="splines", splinesnewdata = newdat, 28 | #' #xlimit=c(0, 4.7), ylimit=c(20, 40)) 29 | #' @export 30 | plotLCTM <- function(m, shape, xlimit=c(0, 4.7), ylimit=c(20, 40), splinesnewdata=NULL){ 31 | 32 | 33 | # Number of classes 34 | k <- m$ng 35 | cols <- gg_color_hue(k) 36 | ests <- as.numeric(m$best) 37 | if(shape=="linear"){ s <- 2 } 38 | if(shape=="quadratic"){ s <- 3 } 39 | 40 | age <- seq(from = xlimit[1], to = xlimit[2], length = 10) 41 | 42 | # plot(agex, f[1,1] + f[1,2]*agex, ylim=ylimit, type="l") 43 | # for(i in 2:k) lines(agex, f[i,1] + f[i,2]*agex) 44 | 45 | ymeantraj <- NULL 46 | if(shape=="linear"){ 47 | f <- ests[k:((k-1)+k*s)] 48 | # arrange as 1 row per class 49 | f <- matrix(f, ncol=k, nrow=s) 50 | for(i in 1:k) ymeantraj[[i]] <- f[i,1] + f[i,2]*age 51 | ymeantrajmat <- sapply(ymeantraj, cbind) 52 | colnames(ymeantrajmat) <- paste("Class", 1:k) 53 | 54 | 55 | ymeantraj <- tidyr::gather(as.data.frame(ymeantrajmat), key="class", value=y) 56 | ymeantraj <- dplyr::bind_cols(age=rep(age, k), y=ymeantraj) 57 | ymeantraj$class <- as.factor(ymeantraj$class) 58 | } 59 | 60 | if(shape=="quadratic"){ 61 | f <- ests[k:((k-1)+k*s)] 62 | # arrange as 1 row per class 63 | f <- matrix(f, ncol=k, nrow=s) 64 | for(i in 1:k) ymeantraj[[i]] <- f[i,1] + f[i,2]*age + f[i,3]*(age^2) 65 | ymeantrajmat <- sapply(ymeantraj, cbind) 66 | ymeantrajmat <- as.data.frame(ymeantrajmat) 67 | colnames(ymeantrajmat) <- paste("Class", 1:k) 68 | ymeantraj <- tidyr::gather(as.data.frame(ymeantrajmat), key="class", value=y) 69 | ymeantraj <- dplyr::bind_cols(age=rep(age, k), y=ymeantraj) 70 | ymeantraj$class <- as.factor(ymeantraj$class) 71 | } 72 | 73 | if(shape=="splines"){ 74 | 75 | preds <- predictY(m, newdata = newdat, var.time = "AGEFUP_C") 76 | 77 | predy <- preds$pred 78 | colnames(predy) <- paste0("Class", 1:k) 79 | ymeantraj <- tidyr::gather(as.data.frame(predy), key="class", value=y) 80 | ymeantraj <- dplyr::bind_cols(age=c(rep(unlist(preds$times), k)), y=ymeantraj) 81 | 82 | 83 | 84 | } 85 | 86 | 87 | g <- ggplot(ymeantraj, aes(x=age, y=y, colour=cols, group=class)) 88 | g <- g + geom_line(aes(colour=class), size=1) 89 | g <- g + xlab("Age (years)") 90 | g <- g + ylab (expression(paste("BMI (kg/",m^2,")", sep=""))) 91 | g <- g + ylim(ylimit) 92 | g <- g + scale_x_continuous(breaks=c(0, 1.7, 3.5, 4.7), labels=c(18, 35, 50, 65)) 93 | g 94 | return(g) 95 | 96 | } 97 | -------------------------------------------------------------------------------- /R/relative_entropy.R: -------------------------------------------------------------------------------- 1 | #' The Relative Entropy 2 | #' 3 | #' @param p is the posterior probabilities of assignment of dimensions, K columns and N rows 4 | #' @return Relative Entropy - where values close to 1 indicate lowest classification uncertainty. In the special case when there is most uncertainty and each individual has equal probability of belonging to each class, E_K=0. Jedidi et al., describes relative entropy as a relative measure of ‘fuzziness’, and suggested cause concern when close to zero, as this implies that the latent class centroids are not sufficiently separated. 5 | #' @examples 6 | #' \dontrun{relative_entropy(p)} 7 | #' @export 8 | 9 | 10 | relative_entropy <- function(p) { 11 | K <- ncol(p) 12 | n <- nrow(p) 13 | 14 | relEntropy <- 1 + (sum(p * log(p), na.rm = TRUE)/(n * log(K))) 15 | 16 | return(relEntropy) 17 | } 18 | -------------------------------------------------------------------------------- /R/residualplot_step1.R: -------------------------------------------------------------------------------- 1 | #' residualplot_step1 2 | #' 3 | #' A wrapper funciton to implement step 1 of the 8 step framework. This is a wrapper fuction to the lcmm/hlme model fit to examine the class-specific residuals in order to aid choice of random effect distribution. 4 | #' 5 | #' @param model fitted hlme or lcmm model using the lcmm R package 6 | #' @param nameofoutcome Name of the longitudinal variable in the dataset 7 | #' @param nameofage Name of the age variable in the dataset 8 | #' @param data Name of the dataframe (long format) used for the regression fit 9 | #' @param type Type of residual plots: lines (spaghetti) or points 10 | #' @return Class-specific residual plots in ggplot style 11 | #' @examples 12 | #' library(ggplot2) 13 | #' data(bmi_long, package = "LCTMtools") 14 | #' require(lcmm) 15 | #' model2class <- lcmm::hlme( 16 | #' fixed = bmi ~ age, 17 | #' mixture = ~age, 18 | #' random = ~ -1, 19 | #' nwg = TRUE, ng = 2, subject = "id", 20 | #' data = data.frame(bmi_long[1:500, ]) 21 | #' ) 22 | #' residualplot_step1(model2class, 23 | #' nameofoutcome = "bmi", 24 | #' nameofage = "age", 25 | #' data = bmi_long, 26 | #' ) 27 | #' @export 28 | 29 | residualplot_step1 <- function (model, nameofoutcome, nameofage, data, 30 | ylimit = c(-50, 50)) 31 | { 32 | require(dplyr) 33 | k <- model$ng 34 | preds <- model$pred 35 | names(preds)[6] <- nameofoutcome 36 | nameofid <- names(model$pred)[1] 37 | test <- dplyr::left_join(preds, model$pprob, .by = nameofid) 38 | test <- dplyr::left_join(test, data, .by = c(nameofid, 39 | nameofoutcome)) 40 | plotvalues <- NULL 41 | for (i in 1:k) { 42 | newplotvalues <- test %>% filter(class == i) %>% mutate(Residuals = get(nameofoutcome) - 43 | eval(parse(text = paste0("pred_ss", i)))) 44 | plotvalues <- rbind(plotvalues, newplotvalues) 45 | plotvaluessub <- plotvalues %>% filter(class == i) 46 | pname <- paste0("p", i) 47 | assign(pname, ggplot2::ggplot(data = plotvaluessub, aes(x = get(nameofage), 48 | y = Residuals, group = class)) + theme(axis.text = element_text(size = 16), 49 | text = element_text(size = 16)) + geom_point() + stat_summary(fun.y = mean, geom = "line", size = 3, 50 | col = "CadetBlue", group = 1) + ggtitle("Residuals in class", 51 | i) + ylim(ylimit)) 52 | print(eval(parse(text = (paste0("p", i))))) 53 | plotname <- paste0("p", i, ".png") 54 | ggplot2::ggsave(filename = plotname) 55 | } 56 | return(as.list(get(dput(paste0("p", 1:k))))) 57 | } 58 | 59 | 60 | # 61 | # 62 | # residualplot_step1 <- function(model, nameofoutcome="bmi", nameofage = "age", data = bmi_long, 63 | # ylimit=c(-5,5)){ 64 | # 65 | # require(dplyr) 66 | # k <- model$ng 67 | # preds <- model$pred 68 | # names(preds)[6] <- nameofoutcome 69 | # nameofid <- names(model$pred)[1] 70 | # test <- dplyr::left_join(preds, model$pprob, .by=nameofid) 71 | # test <- dplyr::left_join(test, bmi_long, .by=c(nameofid, nameofoutcome)) 72 | # 73 | # plotvalues <- NULL 74 | # 75 | # for(i in 1:k){ 76 | # 77 | # newplotvalues <- test %>% filter(class==i) %>% mutate(Residuals=get(nameofoutcome)-eval(parse(text=paste0("pred_ss",i)))) 78 | # plotvalues <- rbind(plotvalues, newplotvalues) 79 | # 80 | # plotvaluessub <- plotvalues %>% filter(class==i) 81 | # 82 | # 83 | # 84 | # pname <- paste0("p", i) 85 | # assign(pname, ggplot2::ggplot(data = plotvaluessub, aes(x = age, y = Residuals, group = class))+ 86 | # theme(axis.text=element_text(size=16),text = element_text(size=16)) + 87 | # geom_point() + 88 | # stat_summary(fun.y=mean, geom="line", size = 3, col="CadetBlue", group=1) + 89 | # ggtitle("Residuals in class", i) + 90 | # ylim(ylimit)) 91 | # print(eval(parse(text=(paste0("p",i))))) 92 | # plotname <- paste0("p",i, ".png") 93 | # ggplot2::ggsave(filename=plotname) 94 | # 95 | # } 96 | # # print(ggpubr::ggarrange(eval(parse(text=(paste0("p",1:k)))), width=1, ncol = k)) 97 | # return( as.list(get(dput(paste0("p",1:k)) ))) 98 | # } 99 | # 100 | # 101 | # 102 | # # residualplot_step1 <- function(model, nameofoutcome="bmi", nameofage = "age", data = bmi_long, 103 | # # type = "line", ylimit=c(-5,5)){ 104 | # # k <- model$ng 105 | # # preds <- model$pred 106 | # # names(preds)[6] <- nameofoutcome 107 | # # nameofid <- names(model$pred)[1] 108 | # # names(data)[names(data) == nameofage] <- "ID" 109 | # # nameofage <- names(data)[names(data) == "ID"] 110 | # # 111 | # # 112 | # # test <- dplyr::left_join(preds, model$pprob, .by = nameofid) 113 | # # test <- dplyr::left_join(test, data, .by = c(nameofid, nameofoutcome)) 114 | # # test <- test %>% 115 | # # group_by(class) %>% 116 | # # mutate(Std_resid = resid_ss / sqrt((1 / (length(resid_ss) - 1)) * sum(resid_ss^2))) 117 | # # 118 | # # library(ggplot2) 119 | # # 120 | # # if (type != "point") { 121 | # # p <- ggplot( 122 | # # data = test, 123 | # # aes_string(x = nameofage, y = "Std_resid", group = nameofid) 124 | # # ) + 125 | # # geom_line(alpha = 0.3) + 126 | # # geom_smooth( 127 | # # mapping = aes_string(x = nameofage, y = "Std_resid", group = NULL), 128 | # # method = "loess", colour = "CadetBlue", size = 1.2 129 | # # ) + 130 | # # labs(x = "ID", y = "Standardised residuals") + 131 | # # facet_wrap(~class) 132 | # # } else { 133 | # # p <- ggplot( 134 | # # data = test, 135 | # # aes_string(x = nameofage, y = "Std_resid", group = nameofid) 136 | # # ) + 137 | # # geom_point(alpha = 0.7) + 138 | # # geom_smooth( 139 | # # mapping = aes_string(x = nameofage, y = "Std_resid", group = NULL), 140 | # # method = "loess", colour = "CadetBlue", size = 1.2 141 | # # ) + 142 | # # labs(x = "ID", y = "Standardised residuals") + 143 | # # facet_wrap(~class) 144 | # # } 145 | # # p 146 | # # } 147 | -------------------------------------------------------------------------------- /R/sastraj_to_lctm.R: -------------------------------------------------------------------------------- 1 | #' Converts a SAS proc traj model to the format of R's hlme class 2 | #' 3 | #' @param oe contains model parameter estimates and maximised likelihood, AIC, BIC values 4 | #' @param of contains posterior probabilities 5 | #' @param op contains predictors 6 | #' @param os containts fixed effect and class membershop parameter estimates 7 | #' @return A format to feed into the LCTMtoolkit() R function 8 | #' @examples 9 | #' \dontrun{sastraj_to_lctm(oe, of, op, os) 10 | #' os$PI/100 11 | #' exp(c(M$best[1:4], 0))/(sum(exp(c(M$best[1:4], 0)))) 12 | #' } 13 | #' @export 14 | 15 | sastraj_to_lctm <- function(oe, of, op, os) { 16 | n <- nrow(of) 17 | K <- nrow(os) 18 | mod <- list(NULL) 19 | mod$pprob <- as.data.frame(of[, c("ID", "GROUP", paste0("GRP", 1:K, "PRB", 20 | sep = ""))]) 21 | colnames(mod$pprob) <- c("ID", "class", paste0("prob", 1:K, sep = "")) 22 | mod$call <- "SAS" 23 | mod$os <- os 24 | mod$oe <- oe 25 | mod$of <- of 26 | mod$op <- op 27 | # model$par <- os$PI 28 | model <- mod 29 | return(model) 30 | } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LCTMtools 2 | 3 | Latent Class Trajectory Modelling Tools: an R Package 4 | 5 | Maintainer: This R package is no longer maintained. 6 | Last Updated: August 2019 7 | 8 | 9 | To install the R package, in the R console use the command 10 | ```{r} 11 | install.packages("devtools") 12 | devtools::install_github("hlennon/LCTMtools") 13 | ``` 14 | 15 | 16 | All statistical (R and SAS) codes used to implement Latent Class Trajectory Modelling and the tools described in the manuscript "A framework to construct and interpret Latent Class Trajectory Modelling", are available here and can be downloaded from www.github.com/hlennon/LCTMtools. 17 | 18 | An example (simulated) dataset 'bmi' and 'bmi_long' (long format version) is provided to describe the steps throughout. 19 | 20 | 21 | 22 | ### Reference 23 | Lennon H, Kelly S, Sperrin M, et al., Framework to construct and interpret Latent Class Trajectory Modelling, BMJ Open 2018;8:e020683. 24 | 25 | Available at 26 | https://bmjopen.bmj.com/content/8/7/e020683 27 | 28 | Supplementary material contains extra details: 29 | https://bmjopen.bmj.com/content/bmjopen/8/7/e020683/DC1/embed/inline-supplementary-material-1.pdf?download=true 30 | 31 | 32 | 33 | ## Help Files 34 | There are two help manuals available above: 35 | + 1) The standard R manual detailing the input and outputs of each of the functions, called LCTMtools.pdf 36 | https://github.com/hlennon/LCTMtools/blob/master/vignettes/LCTMtools.pdf 37 | + 2) A vignette with a guided example, named LCTMtools-vignette 38 | http://rpubs.com/hlennon/LCTMtoolsvignette or https://github.com/hlennon/LCTMtools/blob/master/vignettes/LCTMtoolsvignette.pdf 39 | 40 | 41 | ## Brief Example 42 | 43 | ```{r eval=TRUE} 44 | library(LCTMtools) 45 | data(bmi_long, package = "LCTMtools" ) 46 | 47 | 48 | # Use the hlme function from the 'lcmm' R package to fit a 2 class latent class trajectory model 49 | set.seed(100) 50 | library(lcmm) 51 | model2classes <- lcmm::hlme(fixed = bmi ~ age + I(age^2), 52 | mixture= ~ age, 53 | random = ~ age, 54 | ng = 2, 55 | nwg = TRUE, 56 | subject = "id", 57 | data = data.frame(bmi_long[1:500, ]) ) 58 | 59 | 60 | # Compute model adequacy measures 61 | LCTMtoolkit(model2classes) 62 | 63 | 64 | # Compare with a 3 class model 65 | set.seed(100) 66 | model3classes <- lcmm::hlme(fixed = bmi ~ age + I(age^2), 67 | mixture= ~ age, 68 | random = ~ age, 69 | ng = 3, 70 | nwg = TRUE, 71 | subject = "id", 72 | data = data.frame(bmi_long[1:500, ]) ) 73 | 74 | 75 | LCTMtoolkit(model3classes) 76 | 77 | LCTMcompare(model2classes, model3classes) 78 | ``` 79 | 80 | 81 | ### Citation 82 | Please cite as 83 | 84 | Hannah Lennon. {LCTMtools}: Latent Class Trajectory Models tools R Functions. R package version 0.1.2. 85 | 86 | 87 | Lennon H, Kelly S, Sperrin M, et al 88 | Framework to construct and interpret Latent Class Trajectory Modelling 89 | BMJ Open 2018;8:e020683. doi: 10.1136/bmjopen-2017-020683 90 | 91 | 92 | ### Thanks 93 | A special thank you to Charlotte Watson for testing. 94 | 95 | ### Contributing 96 | Please note this R package is no longer maintained. The R package is open. Fork requests for contributions are encouraged. 97 | 98 | Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. 99 | -------------------------------------------------------------------------------- /data/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/data/.DS_Store -------------------------------------------------------------------------------- /data/bmi.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/data/bmi.rda -------------------------------------------------------------------------------- /data/bmi_long.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/data/bmi_long.rda -------------------------------------------------------------------------------- /inst/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/inst/.DS_Store -------------------------------------------------------------------------------- /man/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/man/.DS_Store -------------------------------------------------------------------------------- /man/LCTMcompare.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/LCTMcompare.R 3 | \name{LCTMcompare} 4 | \alias{LCTMcompare} 5 | \title{A model comparison toolkit. 6 | \code{LCTMcompare}} 7 | \usage{ 8 | LCTMcompare(modelA, modelB) 9 | } 10 | \arguments{ 11 | \item{modelA}{is the output from hlme() R model or model is the output of SASmodelbuilder(oe, os, op, of) passed through it} 12 | 13 | \item{modelB}{the model to be compared which is the output from hlme() R model or model is the output of SASmodelbuilder(oe, os, op, of) passed through it} 14 | } 15 | \value{ 16 | A selection of model adequacy tests, including the APPA (average posterior probability of assignment), the OCC (odds of correct classification), entropy $E$, Relative entropy ($E_k$), 17 | } 18 | \description{ 19 | The function LCTMcompare gives a summary of comparison between fitted LCTM models. 20 | } 21 | \examples{ 22 | data(bmi_long, package='LCTMtools') 23 | require(lcmm) 24 | set.seed(999) 25 | data(bmi_long, package = 'LCTMtools' ) 26 | # Use the hlme function from the 'lcmm' R package to fit a 2 class latent class trajectory model 27 | model2classes <- lcmm::hlme(fixed = bmi ~ age + I(age^2), 28 | mixture= ~ age, 29 | random = ~ age, 30 | ng = 2, 31 | nwg = TRUE, 32 | subject = "id", 33 | data = data.frame(bmi_long[1:500, ] )) 34 | # Compute model adequacy measures 35 | LCTMtoolkit(model2classes) 36 | # Compare with a 3 class model 37 | model3classes <- lcmm::hlme(fixed = bmi ~ age + I(age^2), 38 | mixture= ~ age, 39 | random = ~ age, 40 | ng = 3, 41 | nwg = TRUE, 42 | subject = "id", 43 | data = data.frame(bmi_long[1:500, ] )) 44 | LCTMtoolkit(model3classes) 45 | LCTMcompare(model2classes, model3classes) 46 | } 47 | \references{ 48 | \url{https://bmjopen.bmj.com/content/8/7/e020683} 49 | } 50 | -------------------------------------------------------------------------------- /man/LCTMtoolkit.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/LCTMtoolkit.R 3 | \name{LCTMtoolkit} 4 | \alias{LCTMtoolkit} 5 | \title{A toolkit which computes a selection of model adequacy tests 6 | \code{LCTMtoolkit}} 7 | \usage{ 8 | LCTMtoolkit(model) 9 | } 10 | \arguments{ 11 | \item{model}{the models to be compared which is the output from hlme() R model or model is the output of SASmodelbuilder(oe, os, op, of) passed through it} 12 | } 13 | \value{ 14 | A selection of model adequacy tests, including the APPA (average posterior probability of assignment), the OCC (odds of correct classification), entropy $E$, Relative entropy ($E_k$), 15 | } 16 | \description{ 17 | The function LCTMtoolkit computes a selection of model adequacy tests, including the APPA (average posterior probability of assignment), the OCC (odds of correct classification), entropy E, Relative entropy (E_k), odds of correct classification is the ratio of the odds of classification based on the maximum posterior probablity classification rule and the estimated class membership proportions (pi_k) 18 | } 19 | \examples{ 20 | data(bmi_long, package='LCTMtools') 21 | require(lcmm) 22 | model2class <- lcmm::hlme(fixed = bmi ~ age, 23 | mixture= ~ age, 24 | random= ~ age, 25 | nwg=TRUE, ng=2, subject="id", 26 | data=data.frame(bmi_long[1:500, ])) 27 | postprob(model2class) 28 | LCTMtoolkit(model2class) 29 | } 30 | \references{ 31 | \url{https://bmjopen.bmj.com/content/8/7/e020683} 32 | } 33 | -------------------------------------------------------------------------------- /man/LCTMtools.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/LCTMtools.R 3 | \docType{package} 4 | \name{LCTMtools} 5 | \alias{LCTMtools} 6 | \alias{LCTMtools-package} 7 | \title{LCTMtools: A package for computing a number of Latent Class Trajectory Model tools for a given hlme() object or SAS model.} 8 | \description{ 9 | The LCTMtools package provides two categories of important functions: 10 | LCTMtools (to test a models adequacy) and LCTMcompare (to aid model selection). 11 | } 12 | \section{LCTMtools functions}{ 13 | 14 | The LCTMtools functions arw a selection of model adequacy tests for Latent Class Trajectory Models (LCTMs) which include the APPA (average posterior probability of assignment), the OCC (odds of correct classification), entropy, Relative entropy. 15 | } 16 | 17 | -------------------------------------------------------------------------------- /man/actual_proportions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/actual_proportions.R 3 | \name{actual_proportions} 4 | \alias{actual_proportions} 5 | \title{The proportion within each class} 6 | \usage{ 7 | actual_proportions(p) 8 | } 9 | \arguments{ 10 | \item{p}{is the posterior probabilities of assignment of dimensions, K columns and N rows} 11 | } 12 | \value{ 13 | The proportion within each class AFTER class assignment (using max posterior rule) 14 | } 15 | \description{ 16 | \code{actual_proportions} 17 | The proportion within each class AFTER class assignment (using max posterior rule) 18 | } 19 | \examples{ 20 | \dontrun{actual_proportions(p)} 21 | } 22 | -------------------------------------------------------------------------------- /man/appa.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/appa.R 3 | \name{appa} 4 | \alias{appa} 5 | \title{The Average Posterior Probability Assignment (APPA)} 6 | \usage{ 7 | appa(p) 8 | } 9 | \arguments{ 10 | \item{p}{is the posterior probabilities of assignment of dimensions, K columns and N rows} 11 | } 12 | \value{ 13 | The Average Posterior Probability Assignment (APPA) for each class 14 | } 15 | \description{ 16 | \code{appa} 17 | } 18 | \details{ 19 | Computes the Average Posterior Probability Assignment (APPA) for a K latent class trajectory model. 20 | } 21 | \examples{ 22 | \dontrun{appa(p)} 23 | } 24 | -------------------------------------------------------------------------------- /man/bmi.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bmi.R 3 | \docType{data} 4 | \name{bmi} 5 | \alias{bmi} 6 | \title{Body Mass Index (BMI) repeated measures of 10,000 individuals in wide format.} 7 | \format{A wide format data frame of simulated BMI values of 10,000 individuals. 8 | \describe{ 9 | \item{id}{Individual ID} 10 | \item{bmi}{Body mass index of the individual at times T1,T2, T3 and T4, in kg/m^2} 11 | \item{T}{Time of BMI measure, in years} 12 | \item{true_class}{Tag to identify the class the individual BMI data was simulated from} 13 | }} 14 | \usage{ 15 | bmi 16 | } 17 | \description{ 18 | A wide format data frame of simulated BMI values of 10,000 individuals. 19 | } 20 | \keyword{datasets} 21 | -------------------------------------------------------------------------------- /man/bmi_long.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bmi_long.R 3 | \docType{data} 4 | \name{bmi_long} 5 | \alias{bmi_long} 6 | \title{Body Mass Index (BMI) repeated measures of 10,000 individuals in long format.} 7 | \format{A long format data frame of simulated BMI values of 10,000 individuals. 8 | \describe{ 9 | \item{id}{Individual ID} 10 | \item{age}{Age of BMI measure, in years} 11 | \item{bmi}{Body mass index of the individual at times T1,T2, T3 and T4, in kg/m^2} 12 | \item{true_class}{Tag to identify the class the individual BMI data was simulated from} 13 | }} 14 | \usage{ 15 | bmi_long 16 | } 17 | \description{ 18 | A long format data frame of simulated BMI values of 10,000 individuals. 19 | } 20 | \keyword{datasets} 21 | -------------------------------------------------------------------------------- /man/class_assignment.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/class_assignment.R 3 | \name{class_assignment} 4 | \alias{class_assignment} 5 | \title{Maximum class assignment 6 | \code{class_assignment} 7 | Maximum class assignment} 8 | \usage{ 9 | class_assignment(p) 10 | } 11 | \arguments{ 12 | \item{p}{is the posterior probabilities of assignment of dimensions, K columns and N rows} 13 | } 14 | \value{ 15 | This function computes the Average Posterior Probability Assignment (APPA) for a K latent class trajectory model. 16 | } 17 | \description{ 18 | Maximum class assignment 19 | \code{class_assignment} 20 | Maximum class assignment 21 | } 22 | \examples{ 23 | \dontrun{class_assignment(p)} 24 | } 25 | -------------------------------------------------------------------------------- /man/confusion_matrix.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/confusion_matrix.R 3 | \name{confusion_matrix} 4 | \alias{confusion_matrix} 5 | \title{A confusion matrix} 6 | \usage{ 7 | confusion_matrix(model1, model2, "ModelA", "ModelB") 8 | } 9 | \arguments{ 10 | \item{model1}{A fitted model from the lcmm R package (or from SAS passed through the SASmodelbuilder() function)} 11 | 12 | \item{model2}{is the posterior probabilities of assignment of dimensions, K columns and N rows} 13 | 14 | \item{name1}{optional paramter to pre-specify name of model} 15 | 16 | \item{name2}{optional paramter to pre-specify name of model} 17 | } 18 | \value{ 19 | A confusion matrix between two models with the same number of classes 20 | } 21 | \description{ 22 | A matrix, also known as a matching matrix or an error matrix, is a specific table layout that allows visualization of the performance of an algorithm, typically a supervised learning one. Each row of the matrix represents the instances in a predicted class for model 1 while each column represents the instances in class for model 2. The name stems from the fact that it makes it easy to see if the system is confusing two classes (i.e. commonly mislabeling one as another). 23 | } 24 | \examples{ 25 | \dontrun{ 26 | data(bmi_long, package='LCTMtools') 27 | library(lcmm) 28 | model1 <- lcmm::hlme(BMI ~Age, 29 | mixture= ~Age, 30 | random= ~Age, 31 | nwg=TRUE, ng=2, subject='ID', data=data.frame(bmi_long[1:500, ])) 32 | model2 <- lcmm::hlme(BMI ~Age, 33 | mixture= ~Age, 34 | random= ~1, 35 | nwg=FALSE, ng=2, subject='ID', data=data.frame(bmi_long[1:500, ])) 36 | confusion_matrix(model1, model2)} 37 | } 38 | -------------------------------------------------------------------------------- /man/entropy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/entropy.R 3 | \name{entropy} 4 | \alias{entropy} 5 | \title{Entropy} 6 | \usage{ 7 | entropy(p) 8 | } 9 | \arguments{ 10 | \item{p}{is the posterior probabilities of assignment of dimensions, K columns and N rows} 11 | } 12 | \value{ 13 | Entropy value between (0, infinity) 14 | } 15 | \description{ 16 | A global measure of uncertainty with values close to zero implying a good model. Entropy is a global measure of classification uncertainty, which takes into account all N × K posterior probabilities. The entropy of a model is defined as which takes values from [0,infinity), with higher values indicating a larger amount of uncertainty. Entropy values closest to 0 correspond to models with least classification uncertainty. 17 | } 18 | \examples{ 19 | \dontrun{entropy(p)} 20 | } 21 | -------------------------------------------------------------------------------- /man/gg_color_hue.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/gg_color_hue.R 3 | \name{gg_color_hue} 4 | \alias{gg_color_hue} 5 | \title{gg_color_hue} 6 | \usage{ 7 | gg_color_hue(n) 8 | } 9 | \arguments{ 10 | \item{n}{Number of coloures} 11 | } 12 | \value{ 13 | a vector of n colour codes 14 | } 15 | \description{ 16 | Emulate ggplot2 default colour palette 17 | } 18 | \examples{ 19 | gg_color_hue(2) 20 | gg_color_hue(4) 21 | plot(1:10, pch=12, col=gg_color_hue(10), lwd=30, xaxt="n", yaxt="n", ylab="", xlab="") 22 | } 23 | \references{ 24 | https://www.rdocumentation.org/packages/iprior/versions/0.7.1/topics/gg_colour_hue 25 | } 26 | -------------------------------------------------------------------------------- /man/kappa_matrix.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/kappa_matrix.R 3 | \name{kappa_matrix} 4 | \alias{kappa_matrix} 5 | \title{Kappa matrix} 6 | \usage{ 7 | kappa_matrix(ConfMatrix, acc = 2) 8 | } 9 | \arguments{ 10 | \item{ConfMatrix}{A confusion matrix made using confusion_matrix(model1, model2)} 11 | 12 | \item{acc}{The accuracy of the results, defaults to 2 decimal places} 13 | } 14 | \value{ 15 | Unweighted and weighted Kappa value computed using the cohen.kappa() function from the psych R package 16 | } 17 | \description{ 18 | Kappa matrix of cohen's kappa values 19 | } 20 | \examples{ 21 | data(bmi_long, package='LCTMtools') 22 | require(lcmm) 23 | require(psych) 24 | model1 <- hlme(fixed = bmi ~ age, 25 | mixture= ~ age, 26 | random= ~ age, 27 | nwg=TRUE, ng=2, subject="id", data=data.frame(bmi_long[1:500, ])) 28 | 29 | model2 <- hlme(fixed = ~ age, 30 | mixture= ~ age, 31 | random= ~1, nwg=FALSE, ng=2, subject="id", data=data.frame(bmi_long[1:500, ])) 32 | ConfMatrix <- confusion_matrix(model1, model2) 33 | kappa_matrix(ConfMatrix) 34 | } 35 | -------------------------------------------------------------------------------- /man/mismatch.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mismatch.R 3 | \name{mismatch} 4 | \alias{mismatch} 5 | \title{Computes the mismatch of the posterior probabilities (mismatch=actual-estimated)} 6 | \usage{ 7 | mismatch(p, pi) 8 | } 9 | \arguments{ 10 | \item{p}{is the posterior probabilities of assignment of dimensions, K columns and N rows} 11 | 12 | \item{pi}{is the estimated proportion of class membership of length K} 13 | } 14 | \value{ 15 | The mismatch of posterior probabilities 16 | } 17 | \description{ 18 | Computes the mismatch of the posterior probabilities (mismatch=actual-estimated) 19 | } 20 | \examples{ 21 | \dontrun{mismatch(p, pi)} 22 | } 23 | -------------------------------------------------------------------------------- /man/mmlcr_to_lctm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mmlcr_to_lctm.R 3 | \name{mmlcr_to_lctm} 4 | \alias{mmlcr_to_lctm} 5 | \title{Converts an R mmclr model output to the format of R's hlme class} 6 | \usage{ 7 | mmlcr_to_lctm(model) 8 | } 9 | \arguments{ 10 | \item{model}{contains model parameter estimates and maximised likelihood, AIC, BIC values} 11 | } 12 | \value{ 13 | A format to feed into the LCTMtoolkit() R function 14 | } 15 | \description{ 16 | Converts an R mmclr model output to the format of R's hlme class 17 | } 18 | \examples{ 19 | \dontrun{mmlcr_to_lctm(model)} 20 | } 21 | -------------------------------------------------------------------------------- /man/occ.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/occ.R 3 | \name{occ} 4 | \alias{occ} 5 | \title{The odds of correct classification is the ratio of the odds of classification based on the maximum posterior probablity classification rule and the estimated class membership proportions (pi_k).} 6 | \usage{ 7 | occ(p, pi) 8 | } 9 | \arguments{ 10 | \item{p}{is the posterior probabilities of assignment of dimensions, K columns and N rows} 11 | 12 | \item{pi}{is the estimated proportion of class membership of length K} 13 | } 14 | \value{ 15 | The odds of correct classification 16 | } 17 | \description{ 18 | The odds of correct classification is the ratio of the odds of classification based on the maximum posterior probablity classification rule and the estimated class membership proportions (pi_k). 19 | } 20 | \examples{ 21 | \dontrun{occ(p, pi)} 22 | } 23 | -------------------------------------------------------------------------------- /man/plotLCTM.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plotLCTM.R 3 | \name{plotLCTM} 4 | \alias{plotLCTM} 5 | \title{plotLCTM} 6 | \usage{ 7 | plotLCTM(m, shape, xlimit = c(0, 4.7), ylimit = c(20, 40), 8 | splinesnewdata = NULL) 9 | } 10 | \arguments{ 11 | \item{m}{fitted hlme or lcmm model using the lcmm R package} 12 | } 13 | \value{ 14 | A plot in ggplot style 15 | } 16 | \description{ 17 | A wrapper funciton to plot hlme trajectories in ggplot2 style. 18 | This does the same fuction as predictY in the lcmm package. 19 | } 20 | \examples{ 21 | library(ggplot2) 22 | data(bmi_long, package='LCTMtools') 23 | require(lcmm) 24 | model2class <- lcmm::hlme(fixed = bmi ~ age, 25 | mixture= ~ age, 26 | random= ~ age, 27 | nwg=TRUE, ng=2, subject="id", 28 | data=data.frame(bmi_long[1:500, ])) 29 | plotLCTM(model2class, shape="linear") 30 | 31 | library(splines) # For use of natural splines 32 | model2class_splines <- lcmm::hlme(fixed = bmi ~ ns(age, knots=2), 33 | mixture= ~ ns(age, knots=2), 34 | random= ~ age, 35 | nwg=TRUE, ng=2, subject="id", 36 | data=data.frame(bmi_long[1:500, ])) 37 | newdat <- data.frame(age=seq(0, 4.7, length=100)) 38 | #plotLCTM(model2class_splines, shape="splines", splinesnewdata = newdat, 39 | #xlimit=c(0, 4.7), ylimit=c(20, 40)) 40 | } 41 | -------------------------------------------------------------------------------- /man/relative_entropy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/relative_entropy.R 3 | \name{relative_entropy} 4 | \alias{relative_entropy} 5 | \title{The Relative Entropy} 6 | \usage{ 7 | relative_entropy(p) 8 | } 9 | \arguments{ 10 | \item{p}{is the posterior probabilities of assignment of dimensions, K columns and N rows} 11 | } 12 | \value{ 13 | Relative Entropy - where values close to 1 indicate lowest classification uncertainty. In the special case when there is most uncertainty and each individual has equal probability of belonging to each class, E_K=0. Jedidi et al., describes relative entropy as a relative measure of ‘fuzziness’, and suggested cause concern when close to zero, as this implies that the latent class centroids are not sufficiently separated. 14 | } 15 | \description{ 16 | The Relative Entropy 17 | } 18 | \examples{ 19 | \dontrun{relative_entropy(p)} 20 | } 21 | -------------------------------------------------------------------------------- /man/residualplot_step1.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/residualplot_step1.R 3 | \name{residualplot_step1} 4 | \alias{residualplot_step1} 5 | \title{residualplot_step1} 6 | \usage{ 7 | residualplot_step1(model, nameofoutcome, nameofage, data, ylimit = c(-50, 8 | 50)) 9 | } 10 | \arguments{ 11 | \item{model}{fitted hlme or lcmm model using the lcmm R package} 12 | 13 | \item{nameofoutcome}{Name of the longitudinal variable in the dataset} 14 | 15 | \item{nameofage}{Name of the age variable in the dataset} 16 | 17 | \item{data}{Name of the dataframe (long format) used for the regression fit} 18 | 19 | \item{type}{Type of residual plots: lines (spaghetti) or points} 20 | } 21 | \value{ 22 | Class-specific residual plots in ggplot style 23 | } 24 | \description{ 25 | A wrapper funciton to implement step 1 of the 8 step framework. This is a wrapper fuction to the lcmm/hlme model fit to examine the class-specific residuals in order to aid choice of random effect distribution. 26 | } 27 | \examples{ 28 | library(ggplot2) 29 | data(bmi_long, package = "LCTMtools") 30 | require(lcmm) 31 | model2class <- lcmm::hlme( 32 | fixed = bmi ~ age, 33 | mixture = ~age, 34 | random = ~ -1, 35 | nwg = TRUE, ng = 2, subject = "id", 36 | data = data.frame(bmi_long[1:500, ]) 37 | ) 38 | residualplot_step1(model2class, 39 | nameofoutcome = "bmi", 40 | nameofage = "age", 41 | data = bmi_long, 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /man/sastraj_to_lctm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sastraj_to_lctm.R 3 | \name{sastraj_to_lctm} 4 | \alias{sastraj_to_lctm} 5 | \title{Converts a SAS proc traj model to the format of R's hlme class} 6 | \usage{ 7 | sastraj_to_lctm(oe, of, op, os) 8 | } 9 | \arguments{ 10 | \item{oe}{contains model parameter estimates and maximised likelihood, AIC, BIC values} 11 | 12 | \item{of}{contains posterior probabilities} 13 | 14 | \item{op}{contains predictors} 15 | 16 | \item{os}{containts fixed effect and class membershop parameter estimates} 17 | } 18 | \value{ 19 | A format to feed into the LCTMtoolkit() R function 20 | } 21 | \description{ 22 | Converts a SAS proc traj model to the format of R's hlme class 23 | } 24 | \examples{ 25 | \dontrun{sastraj_to_lctm(oe, of, op, os) 26 | os$PI/100 27 | exp(c(M$best[1:4], 0))/(sum(exp(c(M$best[1:4], 0)))) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /vignettes/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/.DS_Store -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /vignettes/Mod_A_SAS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/Mod_A_SAS.png -------------------------------------------------------------------------------- /vignettes/Mod_C_SAS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/Mod_C_SAS.png -------------------------------------------------------------------------------- /vignettes/Mod_D_SAS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/Mod_D_SAS.png -------------------------------------------------------------------------------- /vignettes/Mod_G_SAS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/Mod_G_SAS.png -------------------------------------------------------------------------------- /vignettes/figures/Mod_A_SAS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/figures/Mod_A_SAS.png -------------------------------------------------------------------------------- /vignettes/figures/Mod_C_SAS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/figures/Mod_C_SAS.png -------------------------------------------------------------------------------- /vignettes/figures/Mod_D_SAS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/figures/Mod_D_SAS.png -------------------------------------------------------------------------------- /vignettes/figures/Mod_G_SAS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/figures/Mod_G_SAS.png -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "LCTMtools: Latent Class Trajectory Modelling tools: An R Package" 3 | author: "Hannah Lennon, Charlotte Watson" 4 | date: "`r Sys.Date()`" 5 | output: rmarkdown::html_vignette 6 | vignette: > 7 | %\VignetteIndexEntry{Vignette Title} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ```{r setup, include = FALSE} 13 | library(knitr) 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>" 17 | ) 18 | ``` 19 | 20 | ```{r echo=FALSE} 21 | gg_color_hue <- function(n) { 22 | hues = seq(15, 375, length = n + 1) 23 | hcl(h = hues, l = 65, c = 100)[1:n] 24 | } 25 | ggplot_colours <- gg_color_hue(5) 26 | ``` 27 | 28 | 29 | 30 | ### Motivation 31 | 32 | Latent class trajectory modelling (LCTM) is a relatively new methodology in epidemiology to describe life-course exposures, which simplifies heterogeneous populations into homogeneous patterns or classes. However, for a given dataset, it is possible to derive scores of different models based on number of classes, model structure and trajectory property. 33 | To facilitate generalisability of results in future studies, a systematic framework to derive a core favoured model was described in the manuscript "A framework to construct and interpret latent class trajectory modelling" are available in an R package called LCTMtools. 34 | 35 | The LCTMtools package provides a quick and easy way to summarise and compare the output of fitted Latent class trajectory models objects. It is primarily aimed at researchers with little experience with R to aid in the analysis of model selection, but we hope may be of use to all. 36 | 37 | 38 | This vignette illustrates basic use of the package’s function, LCTMtoolkit, for summarising outputs from fitted Latent class trajectory models objects. 39 | 40 | 41 | To install the R package, in the R console use the command 42 | 43 | > devtools::install_github("hlennon/LCTMtools") 44 | 45 | 46 | 47 | 48 | ### References 49 | 50 | Lennon H, Kelly S, Sperrin M, et al Framework to construct and interpret latent class trajectory modelling BMJ Open 2018;8:e020683. doi: 10.1136/bmjopen-2017-020683 51 | 52 | Available at https://bmjopen.bmj.com/content/8/7/e020683. 53 | 54 | 55 | Supplementary material contains extra details: 56 | https://bmjopen.bmj.com/content/bmjopen/8/7/e020683/DC1/embed/inline-supplementary-material-1.pdf?download=true 57 | 58 | 59 | 60 | ## Example 61 | *Aim*: By modelling BMI as a function of age, identify subgroups of participants with distinct trajectories. We assume an initial $K=5$ number of classes of BMI trajectories, based on available literature to date. 62 | 63 | 64 | 65 | 66 | To illustrate the functions in the package we use long format data frame of Body Mass Index (BMI) repeated measures of 10,000 individuals, which is included in the LCTMtools package called bmi_long. 67 | 68 | An example (simulated) dataset *bmi* is provided to describe the steps throughout, and *bmi_long* is the long format version. 69 | 70 | 71 | Variables included are: 72 | 73 | id - Individual ID 74 | age - Age of BMI measure, in years 75 | bmi - Body mass index of the individual at times T1,T2, T3 and T4, in kg/m^2 true_class - Tag to identify the class the individual BMI data was simulated from 76 | 77 | 78 | To load the data 79 | 80 | ```{r} 81 | library( LCTMtools ) 82 | data( bmi_long, package = "LCTMtools" ) 83 | ``` 84 | 85 | 86 | 87 | Spaghetti plot the data 88 | 89 | ```{r echo=FALSE} 90 | library( ggplot2 ) 91 | ggplot(data = bmi_long, aes(x = age, y = bmi, group=id)) + geom_line(color="grey") + ggtitle("Spaghetti plot of simualted data") + 92 | xlab("Observation Time Point") + 93 | ylab("Y") 94 | 95 | ``` 96 | 97 | 98 | 99 | # An example of the eight step framework for Latent class trajectory modelling 100 | 101 | 102 | 103 | To model longitdinal outcome $y_{ijk}$, for $k=1:K,$ classes, for individual $i$, at time point $j$, $t_j$ there is are many modelling choices that can be used. We illustrate these here giving the equations, and name them models A to G, in the order of increasing complexity. 104 | 105 | 106 | Model A: No random effects model | Fixed effects homoscedastic | - with the interpretation that any deviation of an individuals trajectory from its mean class trajectory is due to random error only | Can be fitted in R or in SAS using the PROC TRAJ Macro (B Jones 2007)| (common residual variance across classes) 107 | 108 | $$y_{ijk}=\beta_0^{(k)} + \beta_1^{(k)} t_{ij} + \beta_2^{(k)} t^2_{ij} + \epsilon_{ij}}, $$ 109 | where the residual variance is assumed equal across all classes, $\epsilon_{ij}\sim N(0, \sigma^2)$. 110 | 111 | 112 | Model B: Fixed effects model with class-specific residual variances 113 | | heteroscedastic 114 | | The same interpretation as Model A with random errors that can be larger and smaller in different classes. 115 | | Can be fit using the R mmlcr package 116 | 117 | $$y_{ijk}=\beta_0^{(k)} + \beta_1^{(k)} t_{ij} + \beta_2^{(k)} t^2_{ij} + \epsilon_{ijk}}, $$ 118 | where the residual variances are assumed different across $\epsilon_{ijk} \sim N(0, \sigma_k^2)$. 119 | 120 | 121 | Model C: Random intercept 122 | The interpretation is allowing individuals to vary in initial weight but each class member is assumed to follow the same shape and magnitude of the mean trajectory 123 | SAS traj 124 | PROC TRAJ 125 | 126 | For $k=1:K,$ classes, for individual $i$, at time point $j$, $t_j$, 127 | $$y_{ijk}=\beta_0^{(k)} + \beta_1^{(k)} t_{ij} + \beta_2^{(k)} t^2_{ij} + b_0^{(k)} + \epsilon_{ij}}, $$ 128 | where the random effect distibruion $b_0 \sim N(0, B)$. 129 | 130 | 131 | Model D: Random slope 132 | Allowing individuals to vary in initial weight and slope of the mean trajectory but same curvature as trajectory 133 | SAS traj 134 | PROC TRAJ 135 | For $k=1:K,$ classes, for individual $i$, at time point $j$, $t_j$, 136 | $$y_{ijk}=\beta_0^{(k)} + \beta_1^{(k)} t_{ij} + \beta_2^{(k)} t^2_{ij} + b_0^{(k)} + + b_1^{(k)} t_{ij} \epsilon_{ij}}, $$ 137 | where the random effects assumed to be distributed as $b_0 \sim N(0, B)$. 138 | 139 | 140 | 141 | Model E: Random quadratic – Common variance structure across classes 142 | Additional freedom of allowing individuals to vary within classes by initial weight, shape and magnitude, however each class is assumed to have the same amount of variability 143 | R lcmm 144 | hlme/lcmm 145 | For $k=1:K,$ classes, for individual $i$, at time point $j$, $t_j$, 146 | $$y_{ijk}=\beta_0^{(k)} + \beta_1^{(k)} t_{ij} + \beta_2^{(k)} t^2_{ij} + b_0^{(k)} + + b_1^{(k)} t_{ij} \epsilon_{ij}}, $$ 147 | where the random effects assumed to be distributed as $b_0 \sim N(0, B)$. 148 | 149 | 150 | Model F and G: Random quadratic – Proportionality constraint to allow variance structures to vary across classes 151 | Increasing flexibility of model E as variance structures are allowed to differ up to a multiplicative factor to allow some classes to have larger or smaller within-class variances. This model is can be thought of more parsimonious version of model G from (reducing the number of variance-covariance parameters to be estimated from 6xK parameters to 6+(K-1) parameters. 152 | R lcmm 153 | hlme/lcmm 154 | 155 | For $k=1:K,$ classes, for individual $i$, at time point $j$, $t_j$, 156 | $$y_{ijk}=\beta_0^{(k)} + \beta_1^{(k)} t_{ij} + \beta_2^{(k)} t^2_{ij} + b_0^{(k)} + + b_1^{(k)} t_{ij} \epsilon_{ij}}, $$ 157 | where the random effects assumed to be distributed as $b_0 \sim N(0, B)$. 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | ## Step 1: Select the form of the random effect structure 168 | To determine the initial working model structure of random effects, the rationale of Verbeke and Molenbergh can be followed to examined the shape of standardised residual plots for each of the $K$ classes in a model with no random effects. 169 | 170 | If the residual profile could be approximated by a flat, straight line or a curve, then a random intercept, slope or quadratic term, respectively, were considered. 171 | 172 | To fit a latent class modelel with no random effects, the lcmm R package this can be used with the specification of $\verb|random=~-1|$. 173 | 174 | ```{r model1, cache=TRUE} 175 | library( lcmm ) 176 | model1 <- lcmm::hlme(fixed=bmi~1+age+I(age^2), 177 | mixture = ~1+age+I(age^2), 178 | random=~-1, 179 | subject="id", 180 | ng=5, 181 | nwg=FALSE, 182 | data=data.frame(bmi_long) 183 | ) 184 | ``` 185 | 186 | 187 | We then feed the fitted model to the step1 function in LCTMtools to examine the class speciifc residuals. 188 | ```{r eval=FALSE, fig.align="center", fig.height=3, fig.width=5, message=FALSE} 189 | residualplot_step1( model1, 190 | nameofoutcome="bmi", nameofage = "age", 191 | data = bmi_long, 192 | ylimit=c(-15,15)) 193 | ``` 194 | 195 | 196 | ## STEP 2 197 | Refine the preliminary working model from step 1 to determine the optimal number of classes, testing $K=1, ... 7$. 198 | The number of classes chosen may be chosen based on the lowest Bayesian information criteria (BIC). 199 | 200 | ```{r wm, cache=TRUE, message=FALSE, warning=FALSE} 201 | set.seed(100) 202 | m.1 <- lcmm::hlme(fixed = bmi ~ 1+ age + I(age^2), 203 | random = ~ 1 + age, 204 | ng = 1, 205 | idiag = FALSE, 206 | data = data.frame(bmi_long[1:500,]), subject = "id") 207 | lin <- c(m.1$ng, m.1$BIC) 208 | 209 | for (i in 2:4) { 210 | mi <- lcmm::hlme(fixed = bmi ~ 1+ age + I(age^2), 211 | mixture = ~ 1 + age + I(age^2), 212 | random = ~ 1 + age, 213 | ng = i, nwg = TRUE, 214 | idiag = FALSE, 215 | data = data.frame(bmi_long[1:500,]), subject = "id") 216 | 217 | lin <- rbind(lin, c(i, mi$BIC)) 218 | } 219 | 220 | modelout <- knitr::kable(lin, col.names = c("k", "BIC"), row.names = FALSE, align = "c") 221 | modelout 222 | ``` 223 | 224 | 225 | ##Step 3 226 | Further refine the model using the favoured K derived in step 2, testing for the optimal model structure. We tested seven models (detailed above and in the supplementary material Table S2 of the accompanying paper), ranging from a simple fixed effects model (model A) through a rudimentary method that allows the residual variances to vary between classes (model B) to a suite of five random effects models with different variance structures (models C-G). 227 | \ 228 | \ 229 | 230 | 231 | * **Model A (SAS, PROC TRAJ)** 232 | 233 | ```{r echo=FALSE, fig.align="center", fig.height=3, fig.width=5, message=FALSE} 234 | include_graphics("figures/Mod_A_SAS.png") 235 | ``` 236 | 237 | 238 | ```{r eval=FALSE} 239 | oe <- read_sas("oe") # e.g for each 240 | model_b <- sastraj_to_lctm(oe, of, op, os) 241 | ``` 242 | 243 | 244 | \ 245 | \ 246 | 247 | * **Model B (R, mmlcr)** 248 | 249 | Use the R package and script from the depreciated \verb|mmlcr| R package from https://cran.r-project.org/src/contrib/Archive/mmlcr/ 250 | 251 | > install.packages("mmlcr_1.3.2.tar.gz", repos = NULL, type = "source") 252 | 253 | or alternatively, save the file "mmlcr.R" into your folder and call the source() command. 254 | 255 | ```{r results="hide", message=FALSE, warning=FALSE} 256 | library( here ) 257 | source( here::here("vignettes", "mmlcr.R") ) 258 | ls() 259 | # model_b <- mmlcr(outer = ~1|id, 260 | # components = list(list(formula = bmi ~ 1 + age +I(age^2), 261 | # class = "normlong", 262 | # min = -1000, 263 | # max = 5000)), 264 | # data = bmi_long[1:400,], 265 | # n.groups = 5, 266 | # max.iter = 2000, 267 | # tol = 0.001 268 | # ) 269 | ``` 270 | 271 | ``` {r, eval=FALSE} 272 | # model_b$BIC 273 | ``` 274 | \ 275 | \ 276 | 277 | * **Model C (SAS, PROC TRAJ)** 278 | 279 | ```{r, echo=FALSE, fig.width=5, fig.align="center", fig.height=3, message=FALSE, warning=FALSE} 280 | include_graphics('Mod_C_SAS.png') 281 | 282 | ``` 283 | \ 284 | \ 285 | 286 | 287 | * **Model D (SAS, PROC TRAJ)** 288 | 289 | ```{r, echo=FALSE, fig.width=5, fig.align="center", fig.height=3} 290 | include_graphics("Mod_D_SAS.png") 291 | ``` 292 | \ 293 | \ 294 | 295 | 296 | * **Model E (R, lcmm)** 297 | ``` {r mode,cache = TRUE, eval=TRUE} 298 | model_e <- hlme(fixed = bmi ~1+ age + I(age^2), 299 | mixture = ~1 + age + I(age^2), 300 | random = ~1 + age, 301 | ng = 5, nwg = F, 302 | idiag = FALSE, 303 | data = data.frame(bmi_long[1:200,]), 304 | subject = "id") 305 | ``` 306 | 307 | ```{r} 308 | model_e$BIC 309 | ``` 310 | \ 311 | \ 312 | 313 | * **Model F (R, lcmm)** 314 | ``` {r modf, cache = TRUE, eval=TRUE} 315 | model_f <- hlme(fixed = bmi ~1+ age + I(age^2), 316 | mixture = ~1 + age + I(age^2), 317 | random = ~1 + age, 318 | ng = 5, nwg = T, 319 | idiag = FALSE, 320 | data = data.frame(bmi_long[1:200,]), subject = "id") 321 | ``` 322 | 323 | ```{r} 324 | model_f$BIC 325 | ``` 326 | \ 327 | \ 328 | 329 | * **Model G (SAS, PROC TRAJ)** 330 | 331 | ```{r, echo=FALSE, fig.width=5, fig.align="center", fig.height=3} 332 | include_graphics("Mod_G_SAS.png") 333 | ``` 334 | 335 | 336 | 337 | ## Step 4 338 | Perform a number of model adequacy assessments. 339 | First, for each participant, calculate the posterior probability of being assigned to each trajectory class and assigned the individual to the class with the highest probability. 340 | An average of these maximum posterior probability of assignments (APPA) above 70%, in all classes, is regarded as acceptable. 341 | Further assess model adequacy using odds of correct classification, mismatch. 342 | 343 | ```{r lctm, cache=TRUE, warning=FALSE, message=FALSE} 344 | LCTMtoolkit( model_f ) 345 | ``` 346 | 347 | ## Step 5 348 | Graphical presentation approaches; 349 | 350 | 1. Plot mean trajectories with time encompassing each class 351 | ```{r} 352 | 353 | ``` 354 | 355 | 356 | 357 | 2. Mean trajectory plots with 95% predictive intervals for each class, which displays the predicted random variation within each class 358 | 359 | ```{r plotpred, cache=TRUE, fig.align="center",fig.width=5, fig.height=4} 360 | datnew <- data.frame(age = seq(18, 65, length = 100)) 361 | plotpred <- predictY(model_f, datnew, var.time ="age", draws = TRUE) 362 | plot(plotpred, lty=1, xlab="Age", ylab="BMI", legend.loc = "topleft", cex=0.75) 363 | 364 | 365 | ``` 366 | 367 | 3. Individual level 'spaghetti plots' with time, depending on sample size maybe use a random sample of participants 368 | ```{r fig.align="center", fig.width=5} 369 | library(ggplot2) 370 | ggplot(bmi_long, aes(x = age, y = bmi)) + geom_line(aes(color = id,group = id), colour = "grey") + xlab("Age") + ylab("BMI") 371 | 372 | ggplot(bmi_long, aes(x = age, y= bmi)) + geom_line(aes(color = true_class, group = id)) + xlab("Age") + ylab("BMI") + labs(color = "Class Assignment") 373 | 374 | ``` 375 | 376 | ## Step 6 377 | Assess model discrimination, including degrees of separation ($DoS_K$), and Elsensohn's envelope of residuals. 378 | 379 | 380 | 381 | ## Step 7 382 | Assessing clinical characterisation and plausibility using four approaches; 383 | 384 | **1.** Assessing the clinical meaningfulness of the trajectory patterns, aiming to include classes with at least 1% capture of the population 385 | 386 | ``` {r pprob, cache=TRUE} 387 | 388 | lcmm::postprob( model_f ) 389 | 390 | ``` 391 | 392 | 393 | **2.** Assessing the clinical plausibility of the trajectory classes 394 | 395 | Use the plots generated in *6.2* to assess whether the predicted trends seem realistic for the group that is being studid. E.g. for studying BMI, a 396 | predicted trend showing a drop to <5 kg/$m^2$ would be unrealistic as this is unsustainable for life. 397 | \ 398 | \ 399 | 400 | **3.** Tabulation of characteristics by latent classes versus conventional categorisations 401 | 402 | Extract class assignments from chosen model using; 403 | 404 | ```{r, eval=FALSE} 405 | model_f$pprob[,1:2] 406 | ``` 407 | and then feed back into main dataset with descriptive variables. 408 | 409 | Then these can be tabulated as needed. 410 | 411 | ```{r, eval=FALSE} 412 | table(x$class) 413 | rbind(by(x$VARIABLE, x$class, meanSD)) 414 | 415 | 416 | ``` 417 | e.t.c.. 418 | 419 | **4.** Concordance of class membership with conventional BMI category membership using the kappa statistic 420 | 421 | ```{r ks, cache=TRUE, eval=FALSE} 422 | # Defining BMI categories, these need to be in equal number to the number of classes derived 423 | library(dplyr) 424 | library(kableExtra) 425 | library(caret) 426 | bmi_long <- bmi_long %>% mutate(bmi_class = case_when(bmi<18.5~ 1, 427 | bmi>=18.5 & bmi<25 ~ 2, 428 | bmi>=25 & bmi<30 ~ 3, 429 | bmi>=30 & bmi<35 ~ 4, 430 | bmi>=35 ~ 5)) 431 | bmi_long$true_class <- as.factor(bmi_long$true_class) 432 | bmi_long$bmi_class <- as.factor(bmi_long$bmi_class) 433 | levels(bmi_long$true_class) <- c("1","2","3", "4", "5") 434 | x <- broom::confusionMatrix(bmi_long$true_class, bmi_long$bmi_class, dnn=c("Latent Class", "BMI Class")) 435 | y <- as.matrix(x$table) 436 | colnames(y) <- c("<18.5", "18.5-24.9", "25 - 29.9", "30.0-34.9", "<35") 437 | kable(y, row.names = T, align="c") %>% 438 | column_spec(1, bold = T, border_right = T) %>% 439 | kable_styling() %>% 440 | add_header_above(c("Latent Class"=1, "BMI Class" = 5)) 441 | ``` 442 | 443 | 444 | 445 | ## Step 8 446 | Conducted sensitivity analyses as appropriate. 447 | 448 | -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/__packages: -------------------------------------------------------------------------------- 1 | base 2 | knitr 3 | LCTMtools 4 | ggplot2 5 | survival 6 | lcmm 7 | here 8 | -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/ks_b172c03810a3605c9042f7aeedb55b3d.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/ks_b172c03810a3605c9042f7aeedb55b3d.rdb -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/ks_b172c03810a3605c9042f7aeedb55b3d.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/ks_b172c03810a3605c9042f7aeedb55b3d.rdx -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/lctm_8fc028651e91f9a2dc024e5ee476be43.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/lctm_8fc028651e91f9a2dc024e5ee476be43.RData -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/lctm_8fc028651e91f9a2dc024e5ee476be43.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/lctm_8fc028651e91f9a2dc024e5ee476be43.rdb -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/mode_365034ed67070d5e4a67d070f837a384.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/mode_365034ed67070d5e4a67d070f837a384.RData -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/mode_365034ed67070d5e4a67d070f837a384.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/mode_365034ed67070d5e4a67d070f837a384.rdb -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/mode_365034ed67070d5e4a67d070f837a384.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/mode_365034ed67070d5e4a67d070f837a384.rdx -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/model1_66a716ae3e03f0eac2b3bc1f6ec01690.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/model1_66a716ae3e03f0eac2b3bc1f6ec01690.RData -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/modf_003c84d0db12ab3e4db589af135952b2.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/modf_003c84d0db12ab3e4db589af135952b2.rdb -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/modf_003c84d0db12ab3e4db589af135952b2.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/modf_003c84d0db12ab3e4db589af135952b2.rdx -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/plotpred_2b9228e8e187dade2d8457efa857f260.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/plotpred_2b9228e8e187dade2d8457efa857f260.rdb -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/plotpred_2b9228e8e187dade2d8457efa857f260.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/plotpred_2b9228e8e187dade2d8457efa857f260.rdx -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/pprob_62a1a4906f1c2035e60addcb2764c199.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/pprob_62a1a4906f1c2035e60addcb2764c199.rdb -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/pprob_62a1a4906f1c2035e60addcb2764c199.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/pprob_62a1a4906f1c2035e60addcb2764c199.rdx -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/pprob_ee61d6d999d6bf13cf513ed80f439002.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/pprob_ee61d6d999d6bf13cf513ed80f439002.RData -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/pprob_ee61d6d999d6bf13cf513ed80f439002.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/pprob_ee61d6d999d6bf13cf513ed80f439002.rdb -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/wm_7d81148f029fa3f335a866d7a95b100c.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/wm_7d81148f029fa3f335a866d7a95b100c.RData -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/wm_7d81148f029fa3f335a866d7a95b100c.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/wm_7d81148f029fa3f335a866d7a95b100c.rdb -------------------------------------------------------------------------------- /vignettes/lctmtools-vignette_cache/html/wm_7d81148f029fa3f335a866d7a95b100c.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlennon/LCTMtools/ba62f239773618bd22afae0ca030ed8a282b2fb2/vignettes/lctmtools-vignette_cache/html/wm_7d81148f029fa3f335a866d7a95b100c.rdx -------------------------------------------------------------------------------- /vignettes/rsconnect/documents/lctmtools-vignette.Rmd/rpubs.com/rpubs/Document.dcf: -------------------------------------------------------------------------------- 1 | name: Document 2 | title: 3 | username: 4 | account: rpubs 5 | server: rpubs.com 6 | hostUrl: rpubs.com 7 | appId: https://api.rpubs.com/api/v1/document/522393/db009581f4d84a689386b9b23bd5a109 8 | bundleId: https://api.rpubs.com/api/v1/document/522393/db009581f4d84a689386b9b23bd5a109 9 | url: http://rpubs.com/publish/claim/522393/4f15e64784204703aabaa035944bfecd 10 | when: 1566852008.35356 11 | --------------------------------------------------------------------------------