Cálculo de la densidad del camino en R usando la densidad del kernel? [cerrado]

13

Tengo un gran archivo de formas (~ 70 MB) de carreteras y quiero convertir esto en una trama con densidad de carreteras en cada celda. Idealmente, me gustaría hacer esto en R junto con las herramientas de línea de comandos GDAL si es necesario.

Mi enfoque inicial fue calcular directamente las longitudes de los segmentos de línea en cada celda según este hilo . Esto produce los resultados deseados, pero es bastante lento incluso para archivos de forma mucho más pequeños que los míos. Aquí hay un ejemplo muy simplificado para el cual los valores de celda correctos son obvios:

require(sp)
require(raster)
require(rgeos)
require(RColorBrewer)

# Create some sample lines
l1 <- Lines(Line(cbind(c(0,1),c(.25,0.25))), ID="a")
l2 <- Lines(Line(cbind(c(0.25,0.25),c(0,1))), ID="b")
sl <- SpatialLines(list(l1,l2))

# Function to calculate lengths of lines in given raster cell
lengthInCell <- function(i, r, l) {
    r[i] <- 1
    rpoly <- rasterToPolygons(r, na.rm=T)
    lc <- crop(l, rpoly)
    if (!is.null(lc)) {
        return(gLength(lc))
    } else {
        return(0)
    }
}

# Make template
rLength <- raster(extent(sl), res=0.5)

# Calculate lengths
lengths <- sapply(1:ncell(rLength), lengthInCell, rLength, sl)
rLength[] <- lengths

# Plot results
spplot(rLength, scales = list(draw=TRUE), xlab="x", ylab="y", 
       col.regions=colorRampPalette(brewer.pal(9, "YlOrRd")), 
       sp.layout=list("sp.lines", sl), 
       par.settings=list(fontsize=list(text=15)))
round(as.matrix(rLength),3)

#### Results
     [,1] [,2]
[1,]  0.5  0.0
[2,]  1.0  0.5

Imgur

¡Se ve bien, pero no escalable! En algunas otras preguntas, la spatstat::density.psp()función se ha recomendado para esta tarea. Esta función utiliza un enfoque de densidad del núcleo. Puedo implementarlo y parece más rápido que el enfoque anterior, pero no tengo claro cómo elegir los parámetros o interpretar los resultados. Aquí está el ejemplo anterior usando density.psp():

require(spatstat)
require(maptools)

# Convert SpatialLines to psp object using maptools library
pspSl <- as.psp(sl)
# Kernel density, sigma chosen more or less arbitrarily
d <- density(pspSl, sigma=0.01, eps=0.5)
# Convert to raster
rKernDensity <- raster(d)
# Values:
round(as.matrix(rKernDensity),3)

#### Results
      [,1] [,2]
[1,] 0.100  0.0
[2,] 0.201  0.1

Pensé que podría ser el caso de que el enfoque del núcleo calcula la densidad en lugar de la longitud por celda, por lo que convertí:

# Convert from density to length per cell for comparison
rKernLength <- rKernDensity * res(rKernDensity)[1] * res(rKernDensity)[2]
round(as.matrix(rKernLength),3)

#### Results
      [,1]  [,2]
[1,] 0.025 0.000
[2,] 0.050 0.025

Pero, en ninguno de los casos, el enfoque del núcleo se acerca a alinearse con el enfoque más directo anterior.

Entonces, mis preguntas son:

  1. ¿Cómo puedo interpretar la salida de la density.pspfunción? ¿Cuáles son las unidades?
  2. ¿Cómo puedo elegir el sigmaparámetro density.psppara que los resultados se alineen con el enfoque más directo e intuitivo anterior?
  3. Bonificación: ¿qué está haciendo realmente la densidad de línea del núcleo? Tengo algún sentido sobre cómo funcionan estos enfoques para los puntos, pero no veo cómo se extiende a las líneas.
Matt SM
fuente

Respuestas:

8

Publiqué esta pregunta en el servidor de listas R-sig-Geo y recibí una respuesta útil de Adrian Baddeley, uno de los autores de las estadísticas . Publicaré mi interpretación de su respuesta aquí para la posteridad.

Adrian señala que la función spatstat::pixellate.psp()coincide mejor con mi tarea. Esta función convierte un patrón de segmento de línea (u SpatialLinesobjeto con conversión) en una imagen de píxeles (o RasterLayercon conversión), donde el valor en cada celda es la longitud de los segmentos de línea que pasan a través de esa celda. ¡Exactamente lo que estoy buscando!

La resolución de la imagen resultante se puede definir con el epsparámetro o el dimyxparámetro, que establece las dimensiones (número de filas y columnas).

require(sp)
require(raster)
require(maptools)
require(spatstat)

# Create some sample lines
l1 <- Lines(Line(cbind(c(0,1),c(.25,0.25))), ID="a")
l2 <- Lines(Line(cbind(c(0.25,0.25),c(0,1))), ID="b")
sl <- SpatialLines(list(l1,l2))

# Convert SpatialLines to psp object using maptools library
pspSl <- as.psp(sl)
# Pixellate with resolution of 0.5, i.e. 2x2 pixels
px <- pixellate(pspSl, eps=0.5)
# This can be converted to raster as desired
rLength <- raster(px)
# Values:
round(as.matrix(rLength),3)

     [,1] [,2]
[1,]  0.5  0.0
[2,]  1.0  0.5

Los resultados son exactamente los deseados.

Adrian también respondió mis preguntas sobre spatstat::density.psp(). Él explica que esta función:

calcula la convolución del núcleo gaussiano con las líneas. Intuitivamente, esto significa que density.psp'difumina' las líneas en un espacio bidimensional. Entonces density(L)es como una versión borrosa de pixellate(L). De hecho, density(L)es muy similar a blur(pixellate(L))donde blurhay otra spatstatfunción que difumina una imagen. [El parámetro] sigmaes el ancho de banda del núcleo gaussiano. El valor de density.psp(L)en un píxel dado u, es algo así como la cantidad total de longitud de línea en un círculo de radio sigma alrededor del píxel u, excepto que es realmente un promedio ponderado de tales contribuciones de diferentes radios de círculo. Las unidades son longitud ^ (- 1), es decir, longitud de línea por unidad de área.

Todavía no me queda claro cuándo density.psp()se preferiría el enfoque de núcleo gaussiano sobre el enfoque más intuitivo de calcular directamente las longitudes de línea pixellate(). Supongo que tendré que dejar eso para los expertos.

Matt SM
fuente