Quick sanity-check for thresholded and survey-weighted models

Posted on
No user picture. Nick Joined: 07/07/2026

Hi all,

I'm trying to run a set of models with a binary outcome variable that also incorporates some survey weights. I'm pretty sure that I'm misspecifying something somewhere (my standard errors are madness), but I'm not 100% sure where. 

In building things out, I'm getting a few worrying error messages: 

-when I try to run the umxThresholdMatrix, I'm getting an "Error in rep(TRUE, nThreshThisVar) : invalid 'times' argument"

-when I try to run the AutoStart, I'm getting an "Error: In model 'PMTMod' column 'unsecureOrd' is not an ordered factor. Use mxFactor() on this column."

-when I run the refModels, I'm getting an "Error: In model 'Saturated PMTMod' column 'unsecureOrd' is not an ordered factor. Use mxFactor() on this column."

Any chance one of you all could look over the code below to help me identify the issue?

Thanks!

******

pmt.std<-na.omit(pmt.std) %>%
 zap_labels()

pmt.std$unsecureOrd<-mxFactor(pmt.std$unsecure, levels=c(0,1))

unsecureThreshold<-umx::umxThresholdMatrix(pmt.std, fullVarNames="unsecureOrd", method="Mehta")

PMTMod<-mxModel(model="PMTMod", type = "RAM",
               manifestVars = c(ta.manifests, ca.manifests, pm.manifests, "unsecureOrd"),
               latentVars = c("ThreatAppraisal", "CopingAppraisal", "ProtectionMotivation"),
               mxPath(from = "ThreatAppraisal", to = ta.manifests, arrows = 1, free = T, values = .1),
               mxPath(from = "ThreatAppraisal", to = ta.manifests[1], arrows = 1, free = F, values = 1),
               mxPath(from = "CopingAppraisal", to = ca.manifests, arrows = 1, free = T, values = .1),
               mxPath(from = "CopingAppraisal", to = ca.manifests[1], arrows = 1, free = F, values = 1),
               mxPath(from = "ProtectionMotivation", to = pm.manifests, arrows = 1, free = T, values = .1),
               mxPath(from = "ProtectionMotivation", to = pm.manifests[1], arrows = 1, free = F, values = 1),
               
               mxPath(from = "ThreatAppraisal", to = "ProtectionMotivation", arrows = 1, free = T, values = .1, labels = "ThA"),
               mxPath(from = "CopingAppraisal", to = "ProtectionMotivation", arrows = 1, free = T, values = .1, labels = "CoA"),
               mxPath(from = "ThreatAppraisal", to = "CopingAppraisal", arrows = 2, free = T, values = .5, labels= "TCr"),
               
               mxPath(from = "ProtectionMotivation", to = "unsecureOrd", arrows = 1, free = T, values = .1, labels = "B"),
               mxPath(from = "ThreatAppraisal", to = "unsecureOrd", arrows = 1, free = T, values = .1, labels = "ThC"),
               mxPath(from = "CopingAppraisal", to = "unsecureOrd", arrows = 1, free = T, values = .1, labels = "CoC"),
               
               mxThreshold(vars="unsecureOrd", nThresh=1, free=T, values=0),
               
               mxPath(from='one', to="unsecureOrd", free=FALSE, arrows=1, values=0),
               mxPath(from="unsecureOrd", free=FALSE, arrows=2, values=1),
               
               mxAlgebra(ThA * B, name = "ThAB"),
               mxAlgebra(CoA * B, name = "CoAB"),
               mxAlgebra(ThA * B + CoA * B, name = "ToTAB"),
               
               mxPath(from=c(ta.manifests, ca.manifests, pm.manifests, "ThreatAppraisal", "CopingAppraisal", "ProtectionMotivation"), arrows=2, free=TRUE, values=.8, lbound=.0001),
               mxPath(from='one', to=c(ta.manifests, ca.manifests, pm.manifests), arrows=1, free=TRUE, values=0),
               mxData(observed = pmt.std, type = "raw", weight = "weight"),
               mxCI(c("ThAB", "CoAB", "TCr", "B", "ThC", "CoC", "ToTAB"))
               )

PMTAuto<-mxAutoStart(PMTMod)
PMTOut<-mxTryHard(PMTAuto, intervals = T)
PMTRef<-mxRefModels(PMTOut, run = T)
PMTFull<-summary(PMTOut, refModels=PMTRef)
 

Replied on Thu, 07/30/2026 - 17:50
No user picture. Nick Joined: Jul 07, 2026

An update - I've simplified the model to a place where the standard errors are making more sense, but I'm still not able to generate refModels for fit statistics.

I'm still getting the following error: "Error: In model 'Saturated PMTMod' column 'unsecureOrd' is not an ordered factor. Use mxFactor() on this column." even though, when I str(pmt.man$unsecureOrd), I get: "Ord.factor w/ 2 levels "0"<"1": 2 2 2 2 1 2 2 1 1 1 ..."

Any help in fixing this would be greatly appreciated.

##########################################

My code looks like the following:

pmt.man$unsecureOrd<-ordered(pmt.man$unsecure, levels=c(0,1))

PMTMMod<-mxModel(model="PMTMMod", type = "RAM",
               manifestVars = c("threat", "coping", "protection", "unsecureOrd"),
               
               mxPath(from = "threat", to = "protection", arrows = 1, free = T, values = .1, labels = "ThA"),
               mxPath(from = "coping", to = "protection", arrows = 1, free = T, values = .1, labels = "CoA"),
               mxPath(from = "threat", to = "coping", arrows = 2, free = T, values = .5, labels= "TCr"),
               
               mxPath(from = "protection", to = "unsecureOrd", arrows = 1, free = T, values = .1, labels = "B"),
               mxPath(from = "threat", to = "unsecureOrd", arrows = 1, free = T, values = .1, labels = "ThC"),
               mxPath(from = "coping", to = "unsecureOrd", arrows = 1, free = T, values = .1, labels = "CoC"),
               
               mxThreshold(vars="unsecureOrd", nThresh=1, free=T),
               
               mxPath(from='one', to="unsecureOrd", free=FALSE, arrows=1, values=0),
               mxPath(from="unsecureOrd", free=FALSE, arrows=2, values=1),
               
               mxAlgebra(ThA * B, name = "ThAB"),
               mxAlgebra(CoA * B, name = "CoAB"),
               mxAlgebra(ThA * B + CoA * B, name = "ToTAB"),
               
               mxPath(from=c("threat", "coping", "protection"), arrows=2, free=TRUE, values=.8, lbound=.0001),
               mxPath(from='one', to=c("threat", "coping", "protection"), arrows=1, free=TRUE, values=0),
               mxData(observed = pmt.man, type = "raw", weight = "weight"),
               mxCI(c("ThA", "CoA", "ThAB", "CoAB", "TCr", "B", "ThC", "CoC", "ToTAB"))
)
 

PMTMOut<-mxTryHard(PMTMMod, intervals = T)
PMTMRef<-mxRefModels(PMTMOut, run = T)

Replied on Fri, 08/21/2026 - 09:40
Picture of user. AdminNeale Joined: Mar 01, 2013

Hi - Sorry you're having trouble with this.  I asked a friendly AI about the error, since without the data I cannot reproduce your error.  The AI thinks that somehow it got corrupted on the way into the model, perhaps by being 

d <- Saturated.PMTMod$data$observed  # substitute the actual model-object name

class(d$unsecureOrd)
is.factor(d$unsecureOrd)
is.ordered(d$unsecureOrd)
levels(d$unsecureOrd)
str(d$unsecureOrd)

is.ordered(d$unsecureOrd) must be TRUE.

A common cause is converting the data to a matrix, which cannot preserve a factor column alongside numeric columns:
# Risky: may destroy factor classes
mxData(as.matrix(pmt.man), type = "raw")
Other common causes are:

  • applying mxFactor() to pmt.man but supplying a different data frame to the model;
  • subsequently using ifelse(), as.numeric(), cbind(), or a data import/reshape step that strips the factor class;
  • constructing the saturated model before converting the variable and then not replacing its embedded mxData;
  • modifying one twin/group dataset but not the dataset used by the saturated model.

The safest sequence is:
pmt.man$unsecureOrd <- OpenMx::mxFactor(
 pmt.man$unsecureOrd,
 levels = c(0, 1)
)

stopifnot(is.ordered(pmt.man$unsecureOrd))

dataObj <- OpenMx::mxData(
 observed = pmt.man,       # keep this as a data.frame
 type = "raw"
)
The decisive diagnostic is therefore not str(pmt.man$unsecureOrd), which looks correct, but:
is.ordered(Saturated.PMTMod$data$observed$unsecureOrd)
 

OpenMx requires each categorical column in the supplied raw data to remain an ordered factor. OpenMx ordinal-data documentation

 
 
Replied on Wed, 08/26/2026 - 10:19
No user picture. Nick Joined: Jul 07, 2026

In reply to by AdminNeale

Thanks!

Sadly, this doesn't seem to be the root of the problem. is.ordered(pmt.man$unsecureOrd) is, in fact, TRUE, and re-running the safest-sequence above doesn't change the error that I'm getting for the Saturated model. 

Sadly, I can't share the data, for DUA-type reasons. Anything else I could send along that would help to pinpoint the error?