File: multiscale.slice.R

package info (click to toggle)
r-cran-sparr 2.3-16-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 884 kB
  • sloc: makefile: 2
file content (131 lines) | stat: -rw-r--r-- 5,101 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
#' Slicing a multi-scale density/intensity object
#' 
#' Takes slices of a multi-scale density/intensity estimate at desired
#' global bandwidths
#' 
#' Davies & Baddeley (2018) demonstrate that once a multi-scale
#' density/intensity estimate has been computed, we may take slices parallel to
#' the spatial domain of the trivariate convolution to return the estimate at
#' any desired global bandwidth. This function is the implementation thereof
#' based on a multi-scale estimate resulting from a call to
#' \code{\link{multiscale.density}}.
#' 
#' The function returns an error if the
#' requested slices at \code{h0} are not all within the available range of
#' pre-computed global bandwidth scalings as defined by the \code{h0range}
#' component of \code{msob}.
#' 
#' Because the contents of the \code{msob} argument, an object of class
#' \code{\link{msden}}, are returned based on a discretised set of global
#' bandwidth scalings, the function internally computes the desired surface as
#' a pixel-by-pixel linear interpolation using the two discretised global
#' bandwidth rescalings that bound each requested \code{h0}. (Thus, numeric
#' accuracy of the slices is improved with an increase to the \code{dimz}
#' argument of the preceding call to \code{multiscale.density} at the cost of
#' additional computing time.)
#' 
#' @param msob An object of class \code{\link{msden}} giving the multi-scale
#'   estimate from which to take slices.
#' @param h0 Desired global bandwidth(s); the density/intensity estimate
#'   corresponding to which will be returned. A numeric vector. All values \bold{must} be in the
#'   available range provided by \code{msob$h0range}; see `Details'.
#' @param checkargs Logical value indicating whether to check validity of
#'   \code{msob} and \code{h0}. Disable only if you know this check will be
#'   unnecessary.
#'
#' @return If \code{h0} is scalar, an object of class \code{\link{bivden}} with components
#' corresponding to the requested slice at \code{h0}. If \code{h0} is a vector, a list of objects
#' of class \code{\link{bivden}}. 
#' 
#' @author T.M. Davies
#'
#' @seealso \code{\link{multiscale.density}}, \code{\link{bivariate.density}}
#'
#' @references
#' Davies, T.M. and Baddeley A. (2018), Fast computation of
#' spatially adaptive kernel estimates, \emph{Statistics and Computing}, \bold{28}(4), 937-956.
#' 
#' @examples
#' \donttest{
#' data(chorley) # Chorley-Ribble data (package 'spatstat')
#' ch.multi <- multiscale.density(chorley,h0=1,h0fac=c(0.5,2))
#' 
#' available.h0(ch.multi)
#' ch.slices <- multiscale.slice(ch.multi,h0=c(0.7,1.1,1.6))
#' 
#' par(mfcol=c(2,3)) # plot each density and edge-correction surface
#' for(i in 1:3) { plot(ch.slices[[i]]$z); plot(ch.slices[[i]]$q) }
#' }
#' 
#' @export
multiscale.slice <- function(msob,h0,checkargs=TRUE){
  if(checkargs){
    if(!inherits(msob,"msden")) stop("'msob' must be of class \"msden\"")
    if(!is.vector(h0)||!is.numeric(h0)) stop("'h0' must be a numeric vector")
    
    h0 <- sapply(h0,checkit,str="'h0'")
    aran <- msob$h0range
    
    if(!all(sapply(h0,function(x) x>=aran[1]) & sapply(h0,function(x) x<=aran[2]))) stop(paste("at least one requested 'h0' is outside available range of",prange(aran)))
    # was:
    # if(!inside.range(h0,aran)) stop(paste("requested 'h0' outside available range of",prange(aran)))
  }
  
  avail <- names(msob$z)
  zz <- msob$z
  hh <- msob$him
  qq <- msob$q

  hlen <- length(h0)
  if(hlen==1){
    slc <- ms.slice.single(h0,avail,zz,hh,qq)
    result <- list(z=slc$z,h0=h0,hp=msob$hp,h=msob$h/msob$h0*h0,him=slc$h,q=slc$q,gamma=msob$gamma,geometric=msob$geometric,pp=msob$pp) 
    class(result) <- "bivden"
  } else {
    result <- list()
    for(i in 1:hlen){
      slc <- ms.slice.single(h0[i],avail,zz,hh,qq)
      retob <- list(z=slc$z,h0=h0[i],hp=msob$hp,h=msob$h/msob$h0[i]*h0[i],him=slc$h,q=slc$q,gamma=msob$gamma,geometric=msob$geometric,pp=msob$pp) 
      class(retob) <- "bivden"
      result[[i]] <- retob
    }
  }
  
  return(result)
}

ms.slice.single <- function(V,avail,zz,hh,qq,warn=FALSE){
  la <- length(avail)
  if(any(avail==as.character(V))){
    index <- which(avail==as.character(V))
    zres <- zz[[index]]
    hres <- hh[[index]]
    qres <- qq[[index]]
  } else {
    marker <- as.numeric(avail)>V
    if(sum(marker)==la){
      zres <- zz[[1]]
      hres <- hh[[1]]
      qres <- qq[[1]]
      if(warn) warning("lower index mismatch")
    } else if(sum(marker)==0){
      zres <- zz[[la]]
      hres <- hh[[la]]
      qres <- qq[[la]]
      if(warn) warning("upper index mismatch")
    } else {
      marker <- which(marker)[1]
      mindex <- c(marker-1,marker)
      hint <- as.numeric(avail)[mindex]
      move <- (V-hint[1])/diff(hint)
      zdiff <- zz[[mindex[2]]]-zz[[mindex[1]]]
      hdiff <- hh[[mindex[2]]]-hh[[mindex[1]]]
      qdiff <- qq[[mindex[2]]]-qq[[mindex[1]]]
      zres <- zz[[mindex[1]]]+move*zdiff
      hres <- hh[[mindex[1]]]+move*hdiff
      if(!is.null(qq)) qres <- qq[[mindex[1]]]+move*qdiff
      else qres <- NULL
    }
  }
  return(list(z=zres,h=hres,q=qres))
}