File: spatialQuantile.R

package info (click to toggle)
r-cran-spatstat.explore 3.7-0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 3,704 kB
  • sloc: ansic: 4,104; sh: 13; makefile: 5
file content (175 lines) | stat: -rw-r--r-- 5,899 bytes parent folder | download
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
#'
#' Spatially weighted quantile
#'

SpatialMedian <- function(X, ...) {
  UseMethod("SpatialMedian")
}

SpatialQuantile <- function(X, prob=0.5, ...) {
  UseMethod("SpatialQuantile")
}

#' methods for 'ppp' class

SpatialMedian.ppp <- function(X, sigma=NULL, ...,
                             type=4,
                             at=c("pixels", "points"), leaveoneout=TRUE,
                             weights=NULL, 
                             edge=TRUE, diggle=FALSE, verbose=FALSE) {
  SpatialQuantile.ppp(X, sigma=sigma, prob=0.5,
                     ...,
                     type=type,
                     at=at, leaveoneout=leaveoneout,
                     weights=weights,
                     edge=edge, diggle=diggle, verbose=verbose)
}

SpatialQuantile.ppp <- function(X, prob=0.5, sigma=NULL, ...,
                               type=1,
                               at=c("pixels", "points"), leaveoneout=TRUE,
                               weights=NULL,
                               edge=TRUE, diggle=FALSE, verbose=FALSE) {
  if(!is.ppp(X)) stop("X should be a point pattern")
  if(!is.marked(X)) stop("The point pattern X should have marks")
  check.1.real(prob)
  stopifnot(prob >= 0)
  stopifnot(prob <= 1)
  at <- match.arg(at)
  atName <- switch(at, pixels="pixels", points="data points")
  check.1.integer(type)
  type <- as.integer(type)
  if(!any(type == c(1L,4L))) 
    stop(paste("Quantiles of type", type, "are not supported"), call.=FALSE)
  ## extract marks
  X <- coerce.marks.numeric(X)
  m <- marks(X)
  ## multiple columns of marks?
  if(!is.null(dim(m)) && ncol(m) > 1) {
    ## compute separately for each column
    Xlist <- unstack(X)
    Zlist <- lapply(Xlist, SpatialQuantile, prob=prob, sigma=sigma, ...,
                    type=type,
                    at=at, leaveoneout=leaveoneout, weights=weights,
                    edge=edge, diggle=diggle, verbose=verbose)
    ZZ <- switch(at,
                 pixels = as.imlist(Zlist),
                 points = do.call(data.frame, Zlist))
    return(ZZ)
  }
  ## single column of marks
  m <- as.numeric(m)
  nX <- npoints(X)
  #' unique mark values
  um <- sort(unique(m))
  Num <- length(um)
  #' trivial cases
  if(nX == 0 || ((Num == 1) && leaveoneout)) {
    Z <- switch(at,
                pixels = as.im(NA_real_, W=Window(X), ...),
                points = rep(NA_real_, nX))
    attr(Z, "sigma") <- sigma
    return(Z)
  }
  if(Num == 1) {
    Z <- switch(at,
                pixels = as.im(um[1], W=Window(X), ...),
                points = rep(um[1], nX))
    attr(Z, "sigma") <- sigma
    return(Z)
  }
  #' numerical weights 
  if(!is.null(weights)) {
    check.nvector(weights, nX, vname="weights")
    if(any(weights < 0)) stop("Negative weights are not permitted")
    if(sum(weights) < .Machine$double.eps)
      stop("Weights are numerically zero; quantiles are undefined", call.=FALSE)
  }
  #' start main calculation
  ## bandwidth selector
  if(is.function(sigma))
    sigma <- sigma(X, ...)
  #' edge correction has no effect if diggle=FALSE
  #'     (because uniform edge correction cancels)
  edge <- edge && diggle
  #' smoothed intensity of entire pattern
  UX <- unmark(X)
  LX <- density(UX, ...,
                sigma=sigma,
                at=at, leaveoneout=leaveoneout,
                weights=weights,
                edge=edge, diggle=diggle, positive=TRUE)
  #' extract smoothing bandwidth actually used
  sigma <- attr(LX, "sigma")
  varcov <- attr(LX, "varcov")
  #' initialise result
  Z <- LX
  Z[] <- NA
  #' guard against underflow
  tinythresh <- 8 * .Machine$double.eps
  if(underflow <- (min(LX) < tinythresh)) {
    Bad <- (LX < tinythresh)
    warning(paste("Numerical underflow detected at",
                  percentage(Bad, 1), "of", paste0(atName, ";"),
                  "sigma is probably too small"),
            call.=FALSE)
    #' apply l'Hopital's Rule at the problem locations
    tiesfun <- function(x, p=prob, ty=type) {unname(quantile(x, probs=p, type=ty))}
    Z[Bad] <- nnmark(X, at=at, xy=LX, ties=tiesfun)[Bad]
    Good <- !Bad
  }
  #' compute
  for(k in 1:Num) {
    #' cumulative spatial weight of points with marks <= m_[k]
    if(k == Num) {
      Acum.k <- 1
    } else {
      w.k <- (m <= um[k]) * (weights %orifnull% 1)
      Lcum.k <- density(UX,
                        weights=w.k,
                        sigma=sigma, varcov=varcov, 
                        xy=LX,
                        at=at, leaveoneout=leaveoneout,
                        edge=edge, diggle=diggle, positive=TRUE)
      Acum.k <- Lcum.k/LX
    }
    if(k == 1) {
      #' region where quantile is um[1]
      relevant <- (Acum.k >= prob)
      if(underflow) relevant <- relevant & Good
      if(any(relevant)) {
        Z[relevant] <- um[1]
        if(verbose)
          splat("value um[1] =", um[1], "assigned to", sum(relevant), atName)
      }
    } else {
      #' region where quantile is between um[k-1] and um[k]
      unassigned <- (Acum.kprev < prob)
      if(underflow) unassigned <- unassigned & Good
      if(!any(unassigned)) break
      relevant <- unassigned & (Acum.k >= prob)
      if(any(relevant)) {
        if(type == 1) {
          ## left-continuous inverse
          left <- (Acum.k > prob)
          Z[relevant & left] <- um[k-1]
          Z[relevant & !left] <- um[k]
        } else if(type == 4) {
          ## linear interpolation
          Z[relevant] <- um[k-1] +
            (um[k] - um[k-1]) * ((prob - Acum.kprev)/(Acum.k - Acum.kprev))[relevant]
        }
        if(verbose)
          splat("values between",
                paste0("um", paren(k-1, "[")), "=", um[k-1],
                "and",
                paste0("um", paren(k, "[")), "=", um[k],
                "assigned to", sum(relevant), atName)
      }
    }
    Acum.kprev <- Acum.k
  }
  attr(Z, "sigma") <- sigma
  attr(Z, "varcov") <- varcov
  return(Z)
}