File: regression.R

package info (click to toggle)
r-cran-lava 1.8.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,816 kB
  • sloc: sh: 13; makefile: 2
file content (263 lines) | stat: -rw-r--r-- 9,243 bytes parent folder | download | duplicates (2)
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

##' Add regression association to latent variable model
##'
##' Define regression association between variables in a \code{lvm}-object and
##' define linear constraints between model equations.
##'
##'
##' The \code{regression} function is used to specify linear associations
##' between variables of a latent variable model, and offers formula syntax
##' resembling the model specification of e.g. \code{lm}.
##'
##' For instance, to add the following linear regression model, to the
##' \code{lvm}-object, \code{m}:
##' \deqn{ E(Y|X_1,X_2) = \beta_1 X_1 + \beta_2 X_2}
##' We can write
##'
##' \code{regression(m) <- y ~ x1 + x2}
##'
##' Multivariate models can be specified by successive calls with
##' \code{regression}, but multivariate formulas are also supported, e.g.
##'
##' \code{regression(m) <- c(y1,y2) ~ x1 + x2}
##'
##' defines
##' \deqn{ E(Y_i|X_1,X_2) = \beta_{1i} X_1 + \beta_{2i} X_2 }
##'
##' The special function, \code{f}, can be used in the model specification to
##' specify linear constraints. E.g. to fix \eqn{\beta_1=\beta_2}
##' , we could write
##'
##' \code{regression(m) <- y ~ f(x1,beta) + f(x2,beta)}
##'
##' The second argument of \code{f} can also be a number (e.g. defining an
##' offset) or be set to \code{NA} in order to clear any previously defined
##' linear constraints.
##'
##' Alternatively, a more straight forward notation can be used:
##'
##' \code{regression(m) <- y ~ beta*x1 + beta*x2}
##'
##' All the parameter values of the linear constraints can be given as the right
##' handside expression of the assigment function \code{regression<-} (or
##' \code{regfix<-}) if the first (and possibly second) argument is defined as
##' well. E.g:
##'
##' \code{regression(m,y1~x1+x2) <- list("a1","b1")}
##'
##' defines \eqn{E(Y_1|X_1,X_2) = a1 X_1 + b1 X_2}. The rhs argument can be a
##' mixture of character and numeric values (and NA's to remove constraints).
##'
##' The function \code{regression} (called without additional arguments) can be
##' used to inspect the linear constraints of a \code{lvm}-object.
##'
##' @aliases regression regression<- regression<-.lvm regression.lvm regfix
##' regfix regfix<- regfix.lvm regfix<-.lvm
##' @param object \code{lvm}-object.
##' @param value A formula specifying the linear constraints or if
##' \code{to=NULL} a \code{list} of parameter values.
##' @param to Character vector of outcome(s) or formula object.
##' @param from Character vector of predictor(s).
##' @param fn Real function defining the functional form of predictors (for
##' simulation only).
##' @param messages Controls which messages are turned on/off (0: all off)
##' @param additive If FALSE and predictor is categorical a non-additive effect is assumed
##' @param y Alias for 'to'
##' @param x Alias for 'from'
##' @param quick Faster implementation without parameter constraints
##' @param \dots Additional arguments to be passed to the low level functions
##' @usage
##' \method{regression}{lvm}(object = lvm(), to, from, fn = NA,
##' messages = lava.options()$messages, additive=TRUE, y, x, value, ...)
##' \method{regression}{lvm}(object, to=NULL, quick=FALSE, ...) <- value
##' @return A \code{lvm}-object
##' @note Variables will be added to the model if not already present.
##' @author Klaus K. Holst
##' @seealso \code{\link{intercept<-}}, \code{\link{covariance<-}},
##' \code{\link{constrain<-}}, \code{\link{parameter<-}},
##' \code{\link{latent<-}}, \code{\link{cancel<-}}, \code{\link{kill<-}}
##' @keywords models regression
##' @examples
##'
##' m <- lvm() ## Initialize empty lvm-object
##' ### E(y1|z,v) = beta1*z + beta2*v
##' regression(m) <- y1 ~ z + v
##' ### E(y2|x,z,v) = beta*x + beta*z + 2*v + beta3*u
##' regression(m) <- y2 ~ f(x,beta) + f(z,beta)  + f(v,2) + u
##' ### Clear restriction on association between y and
##' ### fix slope coefficient of u to beta
##' regression(m, y2 ~ v+u) <- list(NA,"beta")
##'
##' regression(m) ## Examine current linear parameter constraints
##'
##' ## ## A multivariate model, E(yi|x1,x2) = beta[1i]*x1 + beta[2i]*x2:
##' m2 <- lvm(c(y1,y2) ~ x1+x2)
##'
##' @export
"regression<-" <- function(object,...,value) UseMethod("regression<-")

##' @export
regression.formula <- function(object,...) regression(lvm(),object,...)

##' @export
"regression<-.lvm" <- function(object, to=NULL, quick=FALSE, ..., value) {
    dots <- list(...)
    if (length(dots$additive)>0 && !dots$additive && !inherits(value,"formula")) {
        regression(object,beta=value,...) <- to
        return(object)
    }
    if (!is.null(to) || !is.null(dots$y)) {
        regfix(object, to=to, ...) <- value
        return(object)
    } else  {
        if (is.list(value)) {
            for (v in value) {
                regression(object,...) <- v
            }
            return(object)
        }

        if (inherits(value,"formula")) {
            fff <- procformula(object,value,...)
            object <- fff$object
            lhs <- fff$lhs
            xs <- fff$xs
            ys <- fff$ys
            res <- fff$res
            X <- fff$X

            
        if (fff$iscovar) {
            ## return(covariance(object,var1=decomp.specials(lhs[[1]]),var2=X))
            covariance(object) <- toformula(decomp.specials(lhs[[1]]),X)
            return(object)
        }
        if (!is.null(lhs) && nchar(lhs[[1]])>2 && substr(lhs[[1]],1,2)=="v(") {
            v <- update(value,paste(decomp.specials(lhs),"~."))
            covariance(object,...) <- v
            return(object)
        }

        if (length(lhs)==0) {
            index(object) <- reindex(object)
            return(object)
        }

        for (i in seq_len(length(ys))) {
        y <- ys[i]
        for (j in seq_len(length(xs))) {
          if (length(res[[j]])>1) {
            regfix(object, to=y[1], from=xs[j],...) <- res[[j]][2]
          } else {
            object <- regression(object,to=y[1],from=xs[j],...)
          }
        }
      }
      object$parpos <- NULL
      return(object)
    }
    if (!is.list(value) | length(value)>2) stop("Value should contain names of outcome (to) and predictors (from)")
    if (all(c("to","from")%in%names(value))) {

      xval <- value$x; yval <- value$y
    } else {
      yval <- value[[1]]; xval <- value[[2]]
    }
    regression(object, to=yval, from=xval,...)
  }
}

##' @export
`regression` <-
  function(object,to,from,...) UseMethod("regression")

##' @export
`regression.lvm` <-
    function(object=lvm(),to,from,fn=NA,messages=lava.options()$messages,
             additive=TRUE, y,x,value,...) {
        if (!missing(y)) {
            if (inherits(y,"formula")) y <- all.vars(y)
            to <- y
        }
        if (!missing(x)) {
            if (inherits(x,"formula")) x <- all.vars(x)
            from <- x
        }
        if (!additive) {
            if (!inherits(to,"formula")) to <- toformula(to,from)
            x <- attributes(getoutcome(to))$x
            K <- object$attributes$nordinal[x]
            if (is.null(K) || is.na(K)) {
                K <- list(...)$K
                if (is.null(K)) stop("Supply number of categories, K (or use method 'categorical' before calling 'regression').")
                object <- categorical(object,x,...)
            }
            dots <- list(...);
            dots$K <- K
            dots$x <- object
            dots$formula <- to
            dots$regr.only <- TRUE
            object <- do.call("categorical",dots)
            return(object)
        }


        if (missing(to)) {
            return(regfix(object))
        }
        if ((missing(from) || is.null(from)) &
            is.character(to)) {
          to <- as.formula(paste(to, "~1"))
        }
        if (inherits(to,"formula")) {
          if (!missing(value)) {
                regression(object,to,messages=messages,...) <- value
            } else {
                regression(object,messages=messages,...) <- to
            }
            object$parpos <- NULL
            return(object)
        }
        if (is.list(to)) {
            for (t in to)
                regression(object,messages=messages,...) <- t
            object$parpos <- NULL
            return(object)
        }

        sx <- strsplit(from,"@")
        xx <- sapply(sx, FUN=function(i) i[1])
        ps <- sapply(sx, FUN=function(i) i[2])
        sx <- strsplit(xx,"$",fixed=TRUE)
        xs <- sapply(sx, FUN=function(i) i[1])
        fix <- char2num(sapply(sx, FUN=function(i) i[2]))
        allv <- index(object)$vars

        object <- addvar(object, c(to,xs), messages=messages, reindex=FALSE)

        for (i in to)
            for (j in xs) {
                object$M[j,i] <- 1
                if (!is.na(fn))
                    functional(object,j,i) <- fn
            }

        if (lava.options()$exogenous) {
            newexo <- setdiff(xs,c(to,allv))
            exo <- exogenous(object)
            if (length(newexo)>0)
                exo <- unique(c(exo,newexo))
            exogenous(object) <- setdiff(exo,to)
        }

        if (lava.options()$debug) {
            print(object$fix)
        }
        object$fix[xs,to] <- fix
        object$par[xs,to] <- ps
        object$parpos <- NULL

        index(object) <- reindex(object)
        return(object)
    }