1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
#############################################################################
## Copyright (c) 2010-2022 Rune Haubo Bojesen Christensen
##
## This file is part of the ordinal package for R (*ordinal*)
##
## *ordinal* is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 2 of the License, or
## (at your option) any later version.
##
## *ordinal* is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## A copy of the GNU General Public License is available at
## <https://www.r-project.org/Licenses/> and/or
## <http://www.gnu.org/licenses/>.
#############################################################################
## This file contains:
## A implementation of simple CLMs (simple_clm), i.e., CLMs without
## scale and nominal effects.
simple_clm <-
function(formula, data, weights, start, subset, offset,
doFit = TRUE, na.action, contrasts, model = TRUE,
control = list(),
link = c("logit", "probit", "cloglog", "loglog"),
threshold = c("flexible", "symmetric", "symmetric2", "equidistant"), ...)
{
## Initial argument matching and testing:
mc <- match.call(expand.dots = FALSE)
link <- match.arg(link)
threshold <- match.arg(threshold)
## check for presence of formula:
if(missing(formula)) stop("Model needs a formula")
if(missing(contrasts)) contrasts <- NULL
## set control parameters:
control <- do.call(clm.control, c(control, list(...)))
## Compute: y, X, wts, off, mf:
if (missing(data))
data <- environment(formula)
mf <- match.call(expand.dots = FALSE)
m <- match(c("formula", "data", "subset", "weights", "na.action",
"offset"), names(mf), 0L)
mf <- mf[c(1L, m)]
mf$drop.unused.levels <- TRUE
mf[[1L]] <- as.name("model.frame")
mf <- eval(mf, parent.frame())
## Return model.frame?
if(control$method == "model.frame") return(mf)
y <- model.response(mf, "any") ## any storage mode
if(!is.factor(y)) stop("response needs to be a factor", call.=FALSE)
## design matrix:
mt <- attr(mf, "terms")
X <- if (!is.empty.model(mt))
model.matrix(mt, mf, contrasts)
else cbind("(Intercept)" = rep(1, NROW(y)))
## Test for intercept in X:
Xint <- match("(Intercept)", colnames(X), nomatch = 0)
if(Xint <= 0) {
X <- cbind("(Intercept)" = rep(1, NROW(y)), X)
warning("an intercept is needed and assumed in 'formula'",
call.=FALSE)
} ## intercept in X is guaranteed.
wts <- getWeights(mf)
off <- getOffsetStd(mf)
ylevels <- levels(droplevels(y[wts > 0]))
frames <- list(y=y, ylevels=ylevels, X=X)
## Compute the transpose of the Jacobian for the threshold function,
## tJac and the names of the threshold parameters, alpha.names:
frames <- c(frames, makeThresholds(ylevels, threshold))
## test for column rank deficiency in design matrices:
frames <- drop.cols(frames, silent=TRUE)
## Set envir rho with variables: B1, B2, o1, o2, wts, fitted:
rho <- clm.newRho(parent.frame(), y=frames$y, X=frames$X,
NOM=NULL, S=NULL,
weights=wts, offset=off, S.offset=NULL,
tJac=frames$tJac, control=control)
## Set starting values for the parameters:
start <- set.start(rho, start=start, get.start=missing(start),
threshold=threshold, link=link, frames=frames)
rho$par <- as.vector(start) ## remove attributes
## Set pfun, dfun and gfun in rho:
setLinks(rho, link)
## Possibly return the environment rho without fitting:
if(!doFit) return(rho)
## Fit the clm:
if(control$method == "Newton")
fit <- clm.fit.NR(rho, control)
else
fit <- clm.fit.optim(rho, control$method, control$ctrl)
### NOTE: we could add arg non.conv = c("error", "warn", "message") to
### allow non-converged fits to be returned.
## Modify and return results:
res <- clm.finalize(fit, weights=wts,
coef.names=frames$coef.names,
aliased=frames$aliased)
res$control <- control
res$link <- link
res$start <- start
if(control$method == "Newton" &&
!is.null(start.iter <- attr(start, "start.iter")))
res$niter <- res$niter + start.iter
res$threshold <- threshold
res$call <- match.call()
res$contrasts <- attr(frames$X, "contrasts")
res$na.action <- attr(mf, "na.action")
res$terms <- mt
res$xlevels <- .getXlevels(mt, mf)
res$tJac <- frames$tJac
res$y.levels <- frames$ylevels
## Check convergence:
conv <- conv.check(res, Theta.ok=TRUE, tol=control$tol)
print.conv.check(conv, action=control$convergence) ## print convergence message
res$vcov <- conv$vcov
res$cond.H <- conv$cond.H
res$convergence <- conv[!names(conv) %in% c("vcov", "cond.H")]
res$info <- with(res, {
data.frame("link" = link,
"threshold" = threshold,
"nobs" = nobs,
"logLik" = formatC(logLik, digits=2, format="f"),
"AIC" = formatC(-2*logLik + 2*edf, digits=2,
format="f"),
"niter" = paste(niter[1], "(", niter[2], ")", sep=""),
### NOTE: iterations to get starting values for scale models *are*
### included here.
"max.grad" = formatC(maxGradient, digits=2,
format="e")
## BIC is not part of output since it is not clear what
## the no. observations are.
)
})
class(res) <- "clm"
## add model.frame to results list?
if(model) res$model <- mf
return(res)
}
|