用户比较“ kernel =“ gaussian”`和高斯内核重建结果的“ density.ppp”问题

时间:2018-08-09 09:09:33

标签: r kernel-density spatstat

我目前正在大量使用density.ppp函数,并使用我自己设计的不同内核函数来调用它。 对于我的项目,我还需要“重建”已经可用的内核功能,例如"gaussian""quartic"内核。

因此,我用density.ppp调用了kernel = "gaussian"并将其结果与使用自己的内核函数(生成高斯内核)调用density.ppp的结果进行了比较。

我发现对于高斯内核,其行为与对其他内置内核的相同行为有很大不同。 kernel = "quartic"

我了解这是因为内核值是根据所使用的内核以不同方式计算的。对于除"gaussian"-一个evaluate2Dkernel以外的所有内核。另一方面,kernel = "gaussian"的内核值计算被硬编码为densitypointsEnginesecond.moment.engine

我对此有两个主要问题:

  1. 如果使用at = "points"leaveoneout = FALSE

    # ----- contribution from point itself ----------------
    if(!leaveoneout) {
    # add contribution from point itself
    self <- const
    if(!is.null(weights))
      self <- self * weights
    result <- result + self
    

    }

    被执行。

    在此之前,已设置const。对于除 "gaussian"-一个,我们有const <- 1/sigma^2。对于kernel = "gaussian"const是 然后将其设置为const <- const/(2*pi)以便将其用作 硬编码内核中指数函数之前的常量 值计算:

    # constant factor in density computations
    if(is.null(varcov)) {
      const <- 1/sigma^2 
    } else {
      detSigma <- det(varcov)
      Sinv <- solve(varcov)
      const <- 1/sqrt(detSigma)
    }
    if(isgauss) {
      # absorb leading constant in Gaussian density
      const <- const/(2 * pi)
    }
    

    我认为这是不正确的,因为它应始终为未排除的点添加1/sigma^2,但如果kernel = "gaussian"则应添加1/2*pi*(sigma^2)。我对吗?

  2. 不知何故,我暂时确信,kernel = "gaussian"与高斯核重建的结果也有所不同,因为在second.moment.engine中发现了

    # set up kernel
    xcol.ker <- xstep * c(0:(nc-1),-(nc:1))
    yrow.ker <- ystep * c(0:(nr-1),-(nr:1))
    kerpixarea <- xstep * ystep
    if(identical(kernel, "gaussian")) {
      if(!is.null(sigma)) {
        densX.ker <- dnorm(xcol.ker, sd=sigma)
        densY.ker <- dnorm(yrow.ker, sd=sigma)
        #' WAS:  Kern <- outer(densY.ker, densX.ker, "*") * kerpixarea
        Kern <- outer(densY.ker, densX.ker, "*")
        Kern <- Kern/sum(Kern)
      } else if(!is.null(varcov)) {
        ## anisotropic kernel
        detSigma <- det(varcov)
        Sinv <- solve(varcov)
        halfSinv <- Sinv/2
        constker <- kerpixarea/(2 * pi * sqrt(detSigma))
        xsq <- matrix((xcol.ker^2)[col(Ypad)], ncol=2*nc, nrow=2*nr)
        ysq <- matrix((yrow.ker^2)[row(Ypad)], ncol=2*nc, nrow=2*nr)
        xy <- outer(yrow.ker, xcol.ker, "*")
        Kern <- constker * exp(-(xsq * halfSinv[1,1]
                                 + xy * (halfSinv[1,2]+halfSinv[2,1])
                                 + ysq * halfSinv[2,2]))
        Kern <- Kern/sum(Kern)
      } else 
        stop("Must specify either sigma or varcov")
    } else {
      ## non-Gaussian kernel
      ## evaluate kernel at array of points
      xker <- as.vector(xcol.ker[col(Ypad)])
      yker <- as.vector(yrow.ker[row(Ypad)])
      Kern <- evaluate2Dkernel(kernel, xker, yker,
                               sigma=sigma, varcov=varcov, ...) * kerpixarea
      Kern <- matrix(Kern, ncol=2*nc, nrow=2*nr)
      Kern <- Kern/sum(Kern)
    }
    

    仅当内核不是kerpixarea时,才与"gaussian"进行乘法。但是经过一番测试,我发现由于Kern <- Kern / sum(Kern)行,乘法是否完成并不重要。

    但是我不知道为什么它仍然存在?

    #' WAS: Kern <- outer(densY.ker, densX.ker, "*") * kerpixarea

    注释意味着对kernel = "gaussian"进行了更改以避免这种不必要的计算,对吗?那么为什么其他内核仍然存在呢?

1 个答案:

答案 0 :(得分:0)

density.pppat="points"leaveoneout=FALSE不是默认值的情况下,您在kernel的代码中发现了一个错误。在这种情况下,距离零处的内核值无法正确评估。

该错误将很快在spatstat的开发版本中修复。

关于您的其他问题,恐怕我没有时间解释我们对这段代码的处理方式。它仍在开发中(如注释"Experimental code"所示),以使其运行更快。已有旧代码,因此我们可以检查它是否仍然有效。