Calcolo della densità della strada in R usando la densità del kernel? [chiuso]


13

Ho un grande file di forme (~ 70 MB) di strade e voglio convertirlo in un raster con densità di strade in ogni cella. Idealmente, vorrei farlo in R insieme agli strumenti da riga di comando GDAL, se necessario.

Il mio approccio iniziale era di calcolare direttamente le lunghezze dei segmenti di linea in ogni cella secondo questo thread . Questo produce i risultati desiderati, ma è piuttosto lento anche per i file di forma molto più piccoli dei miei. Ecco un esempio molto semplificato per il quale sono evidenti i valori di cella corretti:

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

Sembra buono, ma non scalabile! In un paio di altre domande la spatstat::density.psp()funzione è stata raccomandata per questo compito. Questa funzione utilizza un approccio di densità del kernel. Sono in grado di implementarlo e sembra più veloce dell'approccio sopra, ma non sono chiaro come scegliere i parametri o interpretare i risultati. Ecco l'esempio sopra 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

Ho pensato che potrebbe essere il caso che l'approccio del kernel calcoli la densità invece della lunghezza per cella, quindi ho convertito:

# 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

Ma, in nessun caso, l'approccio del kernel si avvicina all'allineamento con l'approccio più diretto sopra.

Quindi, le mie domande sono:

  1. Come posso interpretare l'output della density.pspfunzione? Quali sono le unità?
  2. Come posso scegliere il sigmaparametro in density.pspmodo che i risultati si allineino con l'approccio più diretto e intuitivo sopra?
  3. Bonus: cosa sta realmente facendo la densità della linea del kernel? Ho un certo senso di come questi approcci funzionano per i punti, ma non vedo come ciò si estenda alle linee.

Risposte:


8

Ho pubblicato questa domanda sull'elenco di R-sig-Geo e ho ricevuto una risposta utile da Adrian Baddeley, uno degli autori di spatstats . Pubblicherò qui la mia interpretazione della sua risposta per i posteri.

Adrian nota che la funzione spatstat::pixellate.psp()si adatta meglio al mio compito. Questa funzione converte un modello di segmento di linea (o un SpatialLinesoggetto con conversione) in un'immagine pixel (o RasterLayercon conversione), in cui il valore in ciascuna cella è la lunghezza dei segmenti di linea che attraversano quella cella. Esattamente quello che sto cercando!

La risoluzione dell'immagine risultante può essere definita con il epsparametro o il dimyxparametro, che imposta le dimensioni (numero di righe e colonne).

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

I risultati sono esattamente come desiderato.

Adrian ha anche risposto alle mie domande spatstat::density.psp(). Spiega che questa funzione:

calcola la convoluzione del kernel gaussiano con le linee. Intuitivamente, ciò significa che density.psp"spalma" le linee nello spazio bidimensionale. Quindi density(L)è come una versione sfocata di pixellate(L). In effetti density(L)è molto simile a blur(pixellate(L))dove blurè un'altra spatstatfunzione che sfoca un'immagine. [Il parametro] sigmaè la larghezza di banda del kernel gaussiano. Il valore di density.psp(L)in un dato pixel u, è qualcosa di simile alla quantità totale di lunghezza della linea in un cerchio di raggio sigma attorno al pixel u, tranne per il fatto che è davvero una media ponderata di tali contributi da diversi raggi del cerchio. Le unità sono lunghezza ^ (- 1), ovvero la lunghezza della linea per unità di area.

Non mi è ancora chiaro quando l'approccio del kernel gaussiano density.psp()sarebbe preferito rispetto all'approccio più intuitivo del calcolo diretto delle lunghezze delle linee pixellate(). Immagino che dovrò lasciarlo per gli esperti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.