File: interactions.R

package info (click to toggle)
r-cran-spatstat.core 2.4-4-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 6,440 kB
  • sloc: ansic: 4,402; sh: 13; makefile: 5
file content (244 lines) | stat: -rw-r--r-- 8,771 bytes parent folder | download | duplicates (3)
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
#
# interactions.R
#
# Works out which interaction is in force for a given point pattern
#
#  $Revision: 1.26 $  $Date: 2021/12/29 00:24:51 $
#
#
impliedpresence <- function(tags, formula, df, extranames=character(0)) {
  # Determines, for each row of the data frame df,
  # whether the variable called tags[j] is required in the formula
  stopifnot(is.data.frame(df))
  stopifnot(inherits(formula, "formula"))
  stopifnot(is.character(tags))
  stopifnot(is.character(extranames))
#  allvars <- variablesinformula(formula)
  if(any(tags %in% names(df)))
    stop(paste(sQuote("tags"),
               "conflicts with the name of a column of",
               sQuote("df")))
  if(any(extranames %in% names(df)))
    stop(paste(sQuote("extranames"),
               "conflicts with the name of a column of",
               sQuote("df")))
  # answer is a matrix 
  nvars <- length(tags)
  nrows <- nrow(df)
  answer <- matrix(TRUE, nrows, nvars)
  # expand data frame with zeroes for each tags and extranames
  for(v in unique(c(tags, extranames)))
    df[ , v] <- 0
  # loop
  for(i in seq(nrow(df))) {
    # make a fake data frame for the formula
    # using the data frame entries from row i
    # (includes 0 values for all other variables)
    pseudat <- df[i, , drop=FALSE]
    # use this to construct a fake model matrix
    mof0 <- model.frame(formula, pseudat)
    mom0 <- model.matrix(formula, mof0)
    for(j in seq(nvars)) {
      # Reset the variable called tags[j] to 1
      pseudatj <- pseudat
      pseudatj[ , tags[j]] <- 1
      # Now create the fake model matrix
      mofj <- model.frame(formula, pseudatj)
      momj <- model.matrix(formula, mofj)
      # Compare the two matrices
      answer[i,j] <- any(momj != mom0)
    }
  }
  return(answer)
}

active.interactions <- function(object) {
  stopifnot(inherits(object, "mppm"))
  interaction <- object$Inter$interaction
  iformula <- object$iformula
  nenv <- new.env()
  environment(iformula) <- nenv 
  random <- object$random
  if(!is.null(random))
    environment(random) <- nenv

  itags    <- object$Inter$itags
# The following are currently unused  
#  ninter   <- object$Inter$ninter
#  iused    <- object$Inter$iused
#  trivial  <- object$Inter$trivial

  # names of variables
  dat <- object$data
  datanames <- names(dat)
  dfnames <- summary(dat)$dfnames
  nondfnames <- datanames[!(datanames %in% dfnames)]
  nondfnames <- union(nondfnames, c("x", "y"))
  
  # extract data-frame values
  dfdata <- as.data.frame(dat[, dfnames, drop=FALSE], warn=FALSE)
  
  # determine which interaction(s) are in force 
  answer <- impliedpresence(itags, iformula, dfdata, nondfnames)
  if(!is.null(random)) {
    if("|" %in% all.names(random)) {
      ## hack since model.matrix doesn't handle "|" as desired
      rnd <- gsub("|", "/", pasteFormula(random), fixed=TRUE)
      random <- as.formula(rnd, env=environment(random))
    }
    answer2 <- impliedpresence(itags, random, dfdata, nondfnames)
    answer <- answer | answer2
  }
  colnames(answer) <- names(interaction)
  return(answer)
}

impliedcoefficients <- function(object, tag, new.coef=NULL) {
  stopifnot(inherits(object, "mppm"))
  stopifnot(is.character(tag) && length(tag) == 1)
  fitobj      <- object$Fit$FIT
  Vnamelist   <- object$Fit$Vnamelist
  has.random  <- object$Info$has.random
# Not currently used:  
#  fitter      <- object$Fit$fitter
#  interaction <- object$Inter$interaction
#  ninteract   <- object$Inter$ninteract
#  trivial     <- object$Inter$trivial
#  iused       <- object$Inter$iused
  itags       <- object$Inter$itags
  if(!(tag %in% itags))
    stop(paste("Argument", dQuote("tag"),
               "is not one of the interaction names"))
  # (0) Set up
  # Identify the columns of the glm data frame
  # that are associated with this interpoint interaction 
  vnames <- Vnamelist[[tag]]
  if(!is.character(vnames))
    stop("Internal error - wrong format for vnames")
  # Check atomic type of each covariate
  Moadf <- as.list(object$Fit$moadf)
  islog <- sapply(Moadf, is.logical)
  isnum <- sapply(Moadf, is.numeric)
  isfac <- sapply(Moadf, is.factor)
  # Interaction variables must be numeric or logical
  if(any(bad <- !(isnum | islog)[vnames]))
    stop(paste("Internal error: the",
               ngettext(sum(bad), "variable", "variables"),
               commasep(sQuote(vnames[bad])),
               "should be numeric or logical"),
         call.=FALSE)
  # The answer is a matrix of coefficients,
  # with one row for each point pattern,
  # and one column for each vname
  answer <- matrix(, nrow=object$npat, ncol=length(vnames))
  colnames(answer) <- vnames
  
  # (1) make a data frame of covariates
  # Names of all columns in glm data frame
  allnames <- names(Moadf)
  # Extract the design covariates
  df <- as.data.frame(object$data, warn=FALSE)
  # Names of all covariates other than design covariates
  othernames <- allnames[!(allnames %in% names(df))]
  # Add columns in which all other covariates are set to 0, FALSE, etc
  for(v in othernames) {
    df[, v] <- if(isnum[[v]]) 0 else
               if(islog[[v]]) FALSE else
               if(isfac[[v]]) {
                 lev <- levels(Moadf[[v]])
                 factor(lev[1], levels=lev)
               } else sort(unique(Moadf[[v]]))[1]
  }
  # (2) evaluate linear predictor
  Coefs <- new.coef %orifnull% (if(!has.random) coef(fitobj) else fixef(fitobj))
  suppressWarnings({
#  eta0 <- predict(fitobj, newdata=df, type="link")
    eta0 <- GLMpredict(fitobj, data=df, coefs=Coefs,
                       changecoef=TRUE, type="link")
  })
  
  # (3) for each vname in turn,
  # set the value of the vname to 1 and predict again
  for(j in seq_along(vnames)) {
    vnj <- vnames[j]
    df[[vnj]] <- 1
    suppressWarnings({
#    etaj <- predict(fitobj, newdata=df, type="link")
      etaj <- GLMpredict(fitobj, data=df, coefs=Coefs,
                         changecoef=TRUE, type="link")
    })
    answer[ ,j] <- etaj - eta0
    # set the value of this vname back to 0
    df[[vnj]] <- 0
  }
  return(answer)
}



illegal.iformula <- local({

  illegal.iformula <- function(ifmla, itags, dfvarnames) {
    ## THIS IS TOO STRINGENT!
    ## Check validity of the interaction formula.
    ##  ifmla is the formula.
    ##  itags is the character vector of interaction names.
    ## Check whether the occurrences of `itags' in `iformula' are valid:
    ## e.g. no functions applied to `itags[i]'.
    ## Returns NULL if legal, otherwise a character string 
    stopifnot(inherits(ifmla, "formula"))
    stopifnot(is.character(itags))
    ## formula must not have a LHS
    if(length(ifmla) > 2)
      return("iformula must not have a left-hand side")
    ## variables in formula must be interaction tags or data frame variables
    varsinf <- variablesinformula(ifmla)
    if(!all(ok <- varsinf %in% c(itags, dfvarnames))) 
      return(paste(
                   ngettext(sum(!ok), "variable", "variables"),
                   paste(dQuote(varsinf[!ok]), collapse=", "),
                   "not allowed in iformula"))
    ## if formula uses no interaction tags, it's trivial
    if(!any(itags %in% variablesinformula(ifmla)))
      return(NULL)
    ## create terms object
    tt <- attributes(terms(ifmla))
    ## extract all variables appearing in the formula
    vars <- as.list(tt$variables)[-1]
    ##  nvars <- length(vars)
    varexprs <- lapply(vars, as.expression)
    varstrings <- sapply(varexprs, paste)
    ## Each variable may be a name or an expression
    v.is.name <- sapply(vars, is.name)
    ## a term may be an expression like sin(x), poly(x,y,degree=2)
    v.args <- lapply(varexprs, all.vars)
    ##  v.n.args <- sapply(v.args, length)
    v.has.itag <- sapply(lapply(v.args, "%in%", x=itags), any)
    ## interaction tags may only appear as names, not in functions
    if(any(nbg <- v.has.itag & !v.is.name))
      return(paste("interaction tags may not appear inside a function:",
                   paste(dQuote(varstrings[nbg]), collapse=", ")))
    ## Interaction between two itags is not defined
    ## Inspect the higher-order terms
    fax <- tt$factors
    if(prod(dim(fax)) == 0)
      return(NULL)
    ## rows are first order terms, columns are terms of order >= 1
    fvars <- rownames(fax)
    fterms <- colnames(fax)
    fv.args <- lapply(fvars, variablesintext)
    ft.args <- lapply(fterms, variables.in.term, 
                      factors=fax, varnamelist=fv.args)
    ft.itags <- lapply(ft.args, intersect, y=itags)
    if(any(lengths(ft.itags) > 1))
      return("Interaction between itags is not defined")
    return(NULL)
  }

  variables.in.term <- function(term, factors, varnamelist) {
    basis <- (factors[, term] != 0)
    unlist(varnamelist[basis])
  }
  
  illegal.iformula
})