Nothing
library(exametrika)
# M2 factorises a matrix whose size is set by the margins, m = sum(cat - 1) plus
# one block per item pair, so it grows with the square of the item count and the
# factorisation with its cube. The respondent count does not enter: subsetting
# rows leaves m unchanged and saves nothing. Dropping to 12 items takes m from
# 1770 to 630 and these blocks from ~20s to ~1.8s under the reference BLAS that
# CRAN's Windows build ships, which is what the 10-minute checktime limit is
# measured against. Every assertion below is structural -- the rank-deficiency
# rule, m recomputed from the data's own category counts, what print() shows --
# so fewer items tests the same thing.
head_cols <- function(x, j) {
x$ItemLabel <- x$ItemLabel[seq_len(j)]
x$w <- x$w[seq_len(j)]
x$categories <- x$categories[seq_len(j)]
if (!is.null(x$CategoryLabel)) x$CategoryLabel <- x$CategoryLabel[seq_len(j)]
if (!is.null(x$CA)) x$CA <- x$CA[seq_len(j)]
for (f in c("Q", "U", "Z")) {
if (!is.null(x[[f]])) x[[f]] <- x[[f]][, seq_len(j), drop = FALSE]
}
return(x)
}
### GOALS - Mathematica reference data
test <- read.csv(
test_path("fixtures", "mathematica_reference", "Chapter05LCA_Test.csv"),
check.names = FALSE
)
class <- read.csv(
test_path("fixtures", "mathematica_reference", "Chapter05LCA_Class.csv"),
check.names = FALSE
)
items <- read.csv(
test_path("fixtures", "mathematica_reference", "Chapter05LCA_Item.csv"),
check.names = FALSE
)
student <- read.csv(
test_path("fixtures", "mathematica_reference", "Chapter05LCA_Student.csv"),
check.names = FALSE
)
### Setup
# A small binary frame for the tests that only need *a* binary dataset -- which
# method dispatch picks, that a path errors, that two engines agree with each
# other. None of them compares against Mathematica, so J15S500 buys nothing
# there but time, and on CRAN's Windows build time is the scarce thing.
tiny_bin <- dataFormat(
read.csv(test_path("fixtures", "tiny_data", "tinyLCA.csv"), check.names = FALSE),
na = -99
)
# Fitted lazily and cached. skip_on_cran() skips a test_that() body but not
# file-scope setup, so leaving the fit out here would have it run on CRAN for
# the sake of four blocks that are skipped there.
tmp <- dataFormat(J15S500, na = -99)
.lca_model <- NULL
full_model <- function() {
if (is.null(.lca_model)) .lca_model <<- LCA(tmp, ncls = 5)
return(.lca_model)
}
### Tests
test_that("LCA Test Info", {
# The tiny fixtures cross-validate the same quantities against the same
# Mathematica implementation in a fraction of the time (test-lca-tiny.R,
# test-ctt-tiny.R), including the missing-data handling. This full-size
# comparison stays for local runs, where the extra seconds cost nothing.
skip_on_cran()
expect <- test[14:29, 2] |>
unlist() |>
unname() |>
as.numeric()
expect <- expect[c(5, 1, 2, 6, 3, 7, 4, 8:16)]
result <- full_model()$TestFitIndices |> as.numeric()
expect_equal(result, expect, tolerance = 1e-4)
})
test_that("LCA Class Info", {
# The tiny fixtures cross-validate the same quantities against the same
# Mathematica implementation in a fraction of the time (test-lca-tiny.R,
# test-ctt-tiny.R), including the missing-data handling. This full-size
# comparison stays for local runs, where the extra seconds cost nothing.
skip_on_cran()
## TRP
expect <- class[1, 2:6] |>
unlist() |>
unname() |>
as.numeric()
result <- full_model()$TRP |> as.numeric()
expect_equal(result, expect, tolerance = 1e-4)
## LCD
expect <- class[2, 2:6] |>
unlist() |>
unname() |>
as.numeric()
result <- full_model()$LCD |> as.numeric()
expect_equal(result, expect, tolerance = 1e-4)
## CMD
expect <- class[3, 2:6] |>
unlist() |>
unname() |>
as.numeric()
result <- full_model()$CMD |> as.numeric()
expect_equal(result, expect, tolerance = 1e-4)
})
test_that("LCA Item Info", {
# The tiny fixtures cross-validate the same quantities against the same
# Mathematica implementation in a fraction of the time (test-lca-tiny.R,
# test-ctt-tiny.R), including the missing-data handling. This full-size
# comparison stays for local runs, where the extra seconds cost nothing.
skip_on_cran()
## IRP
expect <- items[, 6:10] |>
unlist() |>
unname() |>
as.numeric()
result <- full_model()$IRP |> as.numeric()
expect_equal(result, expect, tolerance = 1e-4)
## FitIndex
expect <- items[, c(15, 11, 12, 16, 13, 17, 14, 18:26)] |>
unlist() |>
unname() |>
as.numeric()
result <- full_model()$ItemFitIndices |>
unlist() |>
as.numeric()
expect_equal(result, expect, tolerance = 1e-4)
})
test_that("LCA Students", {
# The tiny fixtures cross-validate the same quantities against the same
# Mathematica implementation in a fraction of the time (test-lca-tiny.R,
# test-ctt-tiny.R), including the missing-data handling. This full-size
# comparison stays for local runs, where the extra seconds cost nothing.
skip_on_cran()
## Membership
expect <- student[, 6:11] |>
unlist() |>
unname() |>
as.numeric()
result <- full_model()$Students |> as.numeric()
expect_equal(result, expect, tolerance = 1e-4)
})
### S3 dispatch -------------------------------------------------------------
test_that("LCA dispatches on response type", {
# dispatch is about classes, not estimates, so tiny/subset data suffices
expect_true(inherits(LCA(tiny_bin, ncls = 3), "LCA"))
# raw input and a pre-formatted object take the same route
raw_tiny <- read.csv(test_path("fixtures", "tiny_data", "tinyLCA.csv"), check.names = FALSE)
expect_equal(LCA(raw_tiny, na = -99, ncls = 3)$log_lik, LCA(tiny_bin, ncls = 3)$log_lik)
# every response type now has a method, each with its own return class
expect_true(inherits(LCA(head_rows_dat(J21S300, 100), ncls = 2), "ratedLCA"))
expect_true(inherits(
LCA(head_rows_dat(dataFormat(head_cols(J20S600, 12), response.type = "nominal"), 150), ncls = 2),
"nominalLCA"
))
})
### Nominal LCA -------------------------------------------------------------
nominal_data <- dataFormat(head_cols(J20S600, 12), response.type = "nominal")
.nominal <- NULL
nominal_model <- function() {
if (is.null(.nominal)) .nominal <<- LCA(nominal_data, ncls = 3)
return(.nominal)
}
test_that("nominal LCA returns its own class and converges", {
skip_on_cran()
expect_s3_class(nominal_model(), "exametrika")
expect_true(inherits(nominal_model(), "nominalLCA"))
expect_true(nominal_model()$converge)
expect_equal(nominal_model()$n_class, 3)
})
test_that("nominal LCA category profiles are proper distributions", {
skip_on_cran()
probs <- nominal_model()$ICRP[, paste0("class", 1:3)]
expect_true(all(probs >= 0))
# every (item, class) column of category probabilities sums to 1
for (cl in paste0("class", 1:3)) {
sums <- tapply(nominal_model()$ICRP[[cl]], nominal_model()$ICRP$ItemLabel, sum)
expect_equal(as.numeric(sums), rep(1, ncol(nominal_data$Q)), tolerance = 1e-8)
}
# one row per (item, category), so ragged category counts stay aligned
expect_equal(nrow(nominal_model()$ICRP), sum(nominal_data$categories))
})
test_that("nominal LCA reports information criteria only", {
skip_on_cran()
fit <- nominal_model()$TestFitIndices
expect_true(is.na(fit$bench_log_like))
expect_true(all(is.na(c(fit$model_Chi_sq, fit$model_df, fit$CFI, fit$RMSEA))))
expect_true(all(is.finite(c(fit$AIC, fit$BIC, fit$CAIC))))
# information criteria follow the -2 log L + k penalty convention here,
# not the chi-square based one used on the binary path
nparam <- 3 * sum(nominal_data$categories - 1)
expect_equal(fit$AIC, -2 * nominal_model()$log_lik + 2 * nparam)
expect_equal(fit$BIC, -2 * nominal_model()$log_lik + nparam * log(nominal_model()$nobs))
})
test_that("nominal LCA handles ragged category counts", {
set.seed(123)
ncat <- c(2, 3, 4, 5, 3)
raw <- data.frame(ID = paste0("S", 1:200))
for (j in seq_along(ncat)) {
raw[[paste0("Item", j)]] <- sample(seq_len(ncat[j]), 200, replace = TRUE)
}
dat <- dataFormat(raw, response.type = "nominal")
m <- LCA(dat, ncls = 2)
expect_equal(as.vector(dat$categories), ncat)
expect_equal(nrow(m$ICRP), sum(ncat))
sums <- tapply(m$ICRP$class1, m$ICRP$ItemLabel, sum)
expect_equal(as.numeric(sums), rep(1, length(ncat)), tolerance = 1e-8)
})
test_that("ordinal data is routed to the nominal model with a notice", {
expect_message(m <- LCA(J5S1000, ncls = 2), "Latent classes are unordered")
expect_true(inherits(m, "nominalLCA"))
})
test_that("binary data recovers the same solution through the nominal engine", {
# a two-category nominal mixture is the binary LCA model, so the two paths
# must agree up to label switching and local optima
db <- tiny_bin
raw <- cbind(ID = db$ID, as.data.frame(db$U + 1))
dn <- dataFormat(raw, response.type = "nominal")
b <- LCA(db, ncls = 3)
n <- LCA(dn, ncls = 3)
agreement <- sum(apply(table(b$Students[, "Estimate"], n$Students[, "Estimate"]), 1, max))
expect_gt(agreement / nrow(db$U), 0.9)
# the null model does not involve the classes at all, so it must match exactly
expect_equal(n$TestFitIndices$null_log_like, b$TestFitIndices$null_log_like)
})
test_that("nominal LCA prints", {
skip_on_cran()
expect_output(print(nominal_model()), "Item Category Reference Profile")
expect_output(print(nominal_model()), "Number of Latent class")
})
test_that("nominal LCA plots", {
skip_on_cran()
pdf(NULL)
on.exit(dev.off(), add = TRUE)
expect_silent(plot(nominal_model(), type = "ICRP", items = 1:2, nc = 1, nr = 2))
expect_silent(plot(nominal_model(), type = "LCD"))
expect_silent(plot(nominal_model(), type = "CMP", students = 1:2, nc = 1, nr = 2))
# types that need a correct-response rate are not defined without a key
expect_error(plot(nominal_model(), type = "IRP"), "does not correspond")
})
test_that("nominal data given to LRA is handed to LCA", {
small_nominal <- head_rows_dat(nominal_data, 150)
expect_message(m <- LRA(small_nominal, nrank = 4), "Latent ranks require ordered")
expect_true(inherits(m, "nominalLCA"))
# nrank is the LRA spelling of ncls and must not be dropped
expect_equal(m$n_class, 4)
})
### Rated LCA ---------------------------------------------------------------
.rated <- NULL
rated_model <- function() {
if (is.null(.rated)) .rated <<- LCA(J21S300, ncls = 3)
return(.rated)
}
test_that("rated LCA estimates through the nominal engine", {
skip_on_cran()
expect_true(inherits(rated_model(), "ratedLCA"))
expect_true(rated_model()$converge)
# the estimation is the nominal one, so the category profiles must match
nom <- dataFormat(J21S300)
nom$response.type <- "nominal"
n <- LCA(nom, ncls = 3)
expect_equal(rated_model()$ICRP[, paste0("class", 1:3)], n$ICRP[, paste0("class", 1:3)])
expect_equal(rated_model()$log_lik_nominal, n$log_lik)
})
test_that("rated LCA IRP is the keyed category probability", {
skip_on_cran()
dat <- dataFormat(J21S300)
ncat <- as.vector(dat$categories)
offset <- c(0, cumsum(ncat)[-length(ncat)])
keyed <- as.matrix(rated_model()$ICRP[offset + dat$CA, paste0("class", 1:3)])
expect_equal(unname(rated_model()$IRP), unname(keyed))
expect_true(all(rated_model()$IRP >= 0 & rated_model()$IRP <= 1))
# TRP is the weighted item sum of the IRP
expect_equal(rated_model()$TRP, as.vector(t(rated_model()$IRP) %*% dat$w))
})
test_that("rated LCA reports both layers of fit", {
skip_on_cran()
# binary layer keeps the chi-square based indices
expect_true(all(is.finite(unlist(rated_model()$TestFitIndices[c(
"model_Chi_sq", "model_df", "CFI", "RMSEA", "AIC"
)]))))
# nominal layer has information criteria only
expect_true(is.na(rated_model()$TestFitIndicesNominal$model_Chi_sq))
expect_true(is.finite(rated_model()$TestFitIndicesNominal$BIC))
})
test_that("rated LCA does not sort classes by correct rate", {
skip_on_cran()
# Biclustering.rated sorts; LCA must not, because its classes are unordered.
# The seedless EM is deterministic, so an unsorted TRP is evidence enough.
expect_false(identical(rated_model()$TRP, sort(rated_model()$TRP)))
})
test_that("rated LCA prints and plots", {
skip_on_cran()
pdf(NULL)
on.exit(dev.off(), add = TRUE)
expect_output(print(rated_model()), "Binary layer")
expect_output(print(rated_model()), "Nominal layer")
for (ty in c("IRP", "TRP", "ICRP", "LCD", "CMP")) {
expect_silent(plot(rated_model(), type = ty, items = 1:2, students = 1:2, nc = 1, nr = 2))
}
})
### M2 ----------------------------------------------------------------------
test_that("M2 reproduces the worked example of the design memo", {
# Independence model = LCA with a single class: J = 3, Q = 2, S = 100.
# develop/Algorithm_M2.tex gives M2 = 5.52778, df = 3, p = 0.13699, with
# Xi and Delta written out by hand.
rho <- c(.5, .4, .6)
profile <- array(0, dim = c(3, 1, 2))
profile[, 1, 1] <- rho
profile[, 1, 2] <- 1 - rho
p_vec <- c(.5, .4, .6, .25, .32, .26)
out <- exametrika:::m2_core(profile, ncat = rep(2, 3), nobs = 100, p_vec = p_vec)
expect_equal(out$M2, 5.52778, tolerance = 1e-5)
expect_equal(out$df, 3)
expect_equal(out$p, 0.13699, tolerance = 1e-4)
expect_equal(out$m, 6)
expect_equal(out$rank_delta, 3)
# the margin covariance of the memo, to the last printed digit
idx <- exametrika:::m2_margin_index(rep(2, 3))
A <- exametrika:::m2_class_products(profile, idx)
Xi <- exametrika:::m2_xi(profile, A, idx)
Xi_memo <- matrix(c(
.25, 0, 0, .10, .15, 0,
0, .24, 0, .12, 0, .144,
0, 0, .24, 0, .12, .096,
.10, .12, 0, .16, .06, .072,
.15, 0, .12, .06, .21, .048,
0, .144, .096, .072, .048, .1824
), nrow = 6, byrow = TRUE)
expect_equal(unname(Xi), Xi_memo, tolerance = 1e-12)
# and the Jacobian
Delta <- exametrika:::m2_delta(profile, idx, rep(2, 3))
Delta_memo <- matrix(c(
1, 0, 0, 0, 1, 0, 0, 0, 1,
.4, .5, 0, .6, 0, .5, 0, .6, .4
), nrow = 6, byrow = TRUE)
expect_equal(unname(Delta), Delta_memo, tolerance = 1e-12)
})
test_that("M2 is zero when the data match the model exactly", {
profile <- array(0, dim = c(4, 2, 3))
set.seed(9)
for (j in 1:4) {
for (cl in 1:2) {
v <- runif(3, .5, 2)
profile[j, cl, ] <- v / sum(v)
}
}
idx <- exametrika:::m2_margin_index(rep(3, 4))
A <- exametrika:::m2_class_products(profile, idx)
out <- exametrika:::m2_core(profile, rep(3, 4),
nobs = 500,
p_vec = exametrika:::m2_pi(A)
)
expect_lt(out$M2, 1e-16)
})
test_that("the Jacobian loses rank as (ncls - 1)(ncls - 2) / 2", {
skip_on_cran()
# With the class proportions fixed, the second-order margins see the class
# deviations only through their Gram matrix, which is invariant to rotations
# of the (ncls - 1)-dimensional class space.
dat <- dataFormat(head_cols(J20S600, 12), response.type = "nominal")
for (k in 2:4) {
fit <- LCA(dat, ncls = k)
r <- M2(fit, verbose = FALSE)
expect_equal(r$n_param - r$rank_delta, (k - 1) * (k - 2) / 2)
expect_equal(r$df, r$m - r$rank_delta)
}
})
test_that("M2 works from a fitted LCA and prints", {
dat <- head_rows_dat(dataFormat(head_cols(J20S600, 12), response.type = "nominal"), 150)
fit <- LCA(dat, ncls = 3)
r <- M2(fit, verbose = FALSE)
expect_true(inherits(r, "M2"))
expect_true(is.finite(r$M2) && r$M2 > 0)
expect_equal(r$m, sum(dat$categories - 1) +
sum(outer(dat$categories - 1, dat$categories - 1)[upper.tri(diag(ncol(dat$Q)))]))
expect_output(print(r), "Limited-information")
# rated data goes through the same path
expect_true(inherits(M2(LCA(head_rows_dat(J21S300, 100), ncls = 2), verbose = FALSE), "M2"))
# models without a maximum likelihood fit of this kind are refused
expect_error(M2(LCA(tiny_bin, ncls = 3)), "available for models fitted")
})
test_that("add_M2 attaches margin-based fit indices without touching the others", {
skip_on_cran()
dat <- dataFormat(head_cols(J20S600, 12), response.type = "nominal")
fit <- LCA(dat, ncls = 3)
fit2 <- add_M2(fit, verbose = FALSE)
# the response-pattern indices are untouched
expect_equal(fit2$TestFitIndices, fit$TestFitIndices)
expect_true(inherits(fit2$TestFitIndicesM2, "ModelFitM2"))
m <- fit2$TestFitIndicesM2
# the statistic matches a direct call
expect_equal(m$M2, M2(fit, verbose = FALSE)$M2)
# the baseline is the independence model: it reproduces the first-order
# margins, so its degrees of freedom are exactly the second-order cells
ncat <- as.vector(dat$categories)
expect_equal(m$df_null, m$n_margin - sum(ncat - 1))
# a model with classes must fit the cross tables better than independence
expect_lt(m$M2, m$M2_null)
# incremental indices only; information criteria stay on the likelihood side
expect_true(all(is.finite(c(m$NFI, m$RFI, m$IFI, m$TLI, m$CFI, m$RMSEA))))
expect_null(m$AIC)
})
test_that("print shows both worlds of fit indices, and either alone", {
skip_on_cran()
dat <- dataFormat(head_cols(J20S600, 12), response.type = "nominal")
fit <- add_M2(LCA(dat, ncls = 3), verbose = FALSE)
expect_output(print(fit), "Response-pattern based")
expect_output(print(fit), "Margin based")
expect_output(print(fit, fit_indices = "margin"), "Margin based")
out <- capture.output(print(fit, fit_indices = "pattern"))
expect_false(any(grepl("Margin based", out)))
# before add_M2 the margin block is simply absent
bare <- LCA(dat, ncls = 2)
expect_output(print(bare, fit_indices = "margin"), "Call add_M2")
})
test_that("add_M2 refuses models it cannot handle", {
expect_error(add_M2(LCA(tiny_bin, ncls = 3)), "available for models fitted")
})
### M2 for LRA and Biclustering ---------------------------------------------
test_that("M2 for ordinal LRA matches LCA in structure", {
skip_on_cran()
dat <- dataFormat(J5S1000)
a <- M2(suppressMessages(LRA(dat, nrank = 3, method = "isotonic")), verbose = FALSE)
b <- M2(suppressMessages(LCA(dat, ncls = 3)), verbose = FALSE)
# LRA is an ordered LCA: same margins, same parameters, same Jacobian rank.
# Only the estimator differs, so only the statistic itself may differ.
expect_equal(c(a$m, a$n_param, a$rank_delta), c(b$m, b$n_param, b$rank_delta))
expect_true(is.finite(a$M2) && a$M2 > 0)
})
test_that("the Jacobian rank deficiency follows the same rule for LRA", {
skip_on_cran()
dat <- dataFormat(J5S1000)
for (k in 2:4) {
r <- M2(suppressMessages(LRA(dat, nrank = k, method = "isotonic")), verbose = FALSE)
expect_equal(r$n_param - r$rank_delta, (k - 1) * (k - 2) / 2)
}
})
test_that("M2 for biclustering counts field-shared parameters", {
skip_on_cran()
# J20S600 (20 items, 4 categories) rather than J35S500: the assertion is about
# how the parameters are counted, not about the data, and M2 on 35 items costs
# roughly 130x more under the reference BLAS that CRAN's Windows build uses.
dat <- dataFormat(J20S600)
ncat <- 4
ncls <- 4
nfld <- 3
fit <- suppressMessages(Biclustering(dat, ncls = ncls, nfld = nfld, method = "B"))
r <- M2(fit, verbose = FALSE)
# one profile per (field, class), not per (item, class)
expect_equal(r$n_param, nfld * ncls * (ncat - 1))
expect_equal(r$n_param - r$rank_delta, (ncls - 1) * (ncls - 2) / 2)
expect_equal(r$df, r$m - r$rank_delta)
})
test_that("the shared Jacobian doubles the derivative within a field", {
# A pair margin whose two items sit in the same field and name the same
# category is (1/C) sum_c rho^2, so its derivative is twice rho, not rho.
profile <- array(0, dim = c(2, 2, 3))
profile[1, , ] <- profile[2, , ] <- matrix(c(.5, .3, .2, .2, .3, .5), nrow = 2, byrow = TRUE)
idx <- exametrika:::m2_margin_index(rep(3, 2))
D <- exametrika:::m2_delta_shared(profile, idx, rep(3, 2), field = c(1, 1))
# the pair margin (item1 cat1, item2 cat1) is the third row of the pair block
pair_row <- nrow(idx$single) + which(idx$pair[, "cat1"] == 1 & idx$pair[, "cat2"] == 1)
# its derivative with respect to (field 1, category 1, class c) is 2 rho / C
expect_equal(unname(D[pair_row, 1:2]), unname(profile[1, , 1]))
})
test_that("biclustering M2 refuses ragged category counts", {
# J5S1000 has 4/3/4/3/4 categories; a field profile cannot serve them all
dat <- head_rows_dat(dataFormat(J5S1000), 200)
fit <- suppressMessages(Biclustering(dat, ncls = 3, nfld = 2, method = "B"))
expect_error(M2(fit, verbose = FALSE), "same number of categories")
})
test_that("the M2 object stays small whatever the item count", {
skip_on_cran()
# the simulation keeps one of these per fit, so it must not carry the
# residual vector or anything else that grows with m
dat <- dataFormat(J20S600)
fit <- suppressMessages(Biclustering(dat, ncls = 3, nfld = 2, method = "B"))
r <- M2(fit, verbose = FALSE)
expect_lt(as.numeric(object.size(r)), 10000)
expect_null(r$residual)
})
test_that("add_M2 works for LRA and biclustering, with an honest caveat", {
skip_on_cran()
dat <- dataFormat(J5S1000)
# ordinal LRA: order restriction can bind, so the p value is descriptive
fit <- add_M2(suppressMessages(LRA(dat, nrank = 3, method = "isotonic")), verbose = FALSE)
m <- fit$TestFitIndicesM2
expect_true(inherits(m, "ModelFitM2"))
expect_match(m$caveat, "order restriction")
expect_output(print(fit), "Margin based")
expect_output(print(fit), "descriptive only")
fit_gtm <- add_M2(suppressMessages(LRA(dat, nrank = 3, method = "GTM")), verbose = FALSE)
expect_match(fit_gtm$TestFitIndicesM2$caveat, "regularisation")
# the response-pattern indices are untouched, and both blocks can be shown alone
expect_equal(fit$TestFitIndices, suppressMessages(
LRA(dat, nrank = 3, method = "isotonic")
)$TestFitIndices)
out <- capture.output(print(fit, fit_indices = "pattern"))
expect_false(any(grepl("Margin based", out)))
})
test_that("biclustering caveats name the reason that applies", {
# The caveat is a pure function of $model and $estimation (m2_caveat_*), so it
# needs no particular data -- only a fit that records model 2 and the filter.
# A generated 120x12 frame does that in 0.3 s; J35S500 took roughly 20 min
# under the reference BLAS in CRAN's Windows build, which is what sank 1.13.0.
set.seed(1)
Q <- matrix(sample(1:4, 12 * 120, replace = TRUE), nrow = 120, ncol = 12)
colnames(Q) <- paste0("Item", seq_len(12))
dat <- dataFormat(as.data.frame(cbind(ID = seq_len(120), Q)))
b <- add_M2(suppressMessages(Biclustering(dat, ncls = 3, nfld = 2, method = "B")),
verbose = FALSE
)
# the field partition is always taken as given
expect_match(b$TestFitIndicesM2$caveat, "field partition")
expect_false(grepl("regularisation", b$TestFitIndicesM2$caveat))
r <- add_M2(suppressMessages(Biclustering(dat,
ncls = 3, nfld = 2,
method = "R", estimation = "GTM"
)), verbose = FALSE)
expect_match(r$TestFitIndicesM2$caveat, "field partition")
expect_match(r$TestFitIndicesM2$caveat, "regularisation")
expect_output(print(b), "Margin based")
})
test_that("the margin baseline does not depend on the model family", {
skip_on_cran()
# the independence model is fitted to the data, not to the model, so the
# same data gives the same baseline whichever arm was run
dat <- dataFormat(J5S1000)
a <- add_M2(suppressMessages(LRA(dat, nrank = 3, method = "isotonic")), verbose = FALSE)
b <- add_M2(suppressMessages(LCA(dat, ncls = 4)), verbose = FALSE)
expect_equal(a$TestFitIndicesM2$M2_null, b$TestFitIndicesM2$M2_null)
expect_equal(a$TestFitIndicesM2$df_null, b$TestFitIndicesM2$df_null)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.