Calculando a densidade da estrada em R usando a densidade do kernel? [fechadas]

13

Eu tenho um grande arquivo de forma (~ 70 MB) de estradas e quero convertê-lo em um raster com densidade de estrada em cada célula. Idealmente, eu gostaria de fazer isso no R junto com as ferramentas de linha de comando GDAL, se necessário.

Minha abordagem inicial foi calcular diretamente os comprimentos dos segmentos de linha em cada célula conforme esse segmento . Isso produz os resultados desejados, mas é bastante lento, mesmo para arquivos de forma muito menores que os meus. Aqui está um exemplo muito simplificado para o qual os valores corretos das células são óbvios:

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

Parece bom, mas não escalável! Em algumas outras questões, a spatstat::density.psp()função foi recomendada para esta tarefa. Esta função usa uma abordagem de densidade do kernel. Eu sou capaz de implementá-lo e parece mais rápido que a abordagem acima, mas não sei como escolher os parâmetros ou interpretar os resultados. Aqui está o exemplo acima 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

Eu pensei que poderia ser o caso de a abordagem do kernel calcular a densidade em oposição ao comprimento por célula, então eu converti:

# 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

Mas, em nenhum dos casos, a abordagem do kernel chega perto de se alinhar com a abordagem mais direta acima.

Então, minhas perguntas são:

  1. Como posso interpretar a saída da density.pspfunção? Quais são as unidades?
  2. Como posso escolher o sigmaparâmetro density.psppara que os resultados se alinhem à abordagem mais direta e intuitiva acima?
  3. Bônus: o que a densidade de linha do kernel está realmente fazendo? Eu tenho algum senso de como essas abordagens funcionam para obter pontos, mas não vejo como isso se estende às linhas.
Matt SM
fonte

Respostas:

8

Publiquei esta pergunta no listserv R-sig-Geo e recebi uma resposta útil de Adrian Baddeley, um dos autores de spatstats . Vou postar aqui minha interpretação de sua resposta para a posteridade.

Adrian observa que a função spatstat::pixellate.psp()é uma melhor correspondência para a minha tarefa. Essa função converte um padrão de segmento de linha (ou SpatialLinesobjeto com conversão) em uma imagem de pixel (ou RasterLayercom conversão), em que o valor em cada célula é o comprimento dos segmentos de linha que passam por essa célula. Exatamente o que estou procurando!

A resolução da imagem resultante pode ser definida com o epsparâmetro ou o dimyxparâmetro, que define as dimensões (número de linhas e colunas).

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

Os resultados são exatamente como desejados.

Adrian também respondeu minhas perguntas sobre spatstat::density.psp(). Ele explica que esta função:

calcula a convolução do kernel gaussiano com as linhas. Intuitivamente, isso significa que density.psp'mancha' as linhas no espaço bidimensional. Assim density(L)é como uma versão borrada de pixellate(L). De fato, density(L)é muito semelhante a blur(pixellate(L))onde blurestá outra spatstatfunção que desfoca uma imagem. [O parâmetro] sigmaé a largura de banda do kernel gaussiano. O valor de density.psp(L)um dado pixel u é algo como a quantidade total de comprimento de linha em um círculo de raio sigma ao redor do pixel u, exceto que é realmente uma média ponderada dessas contribuições de diferentes raios do círculo. As unidades são comprimento ^ (- 1), ou seja, comprimento da linha por unidade de área.

Ainda não está claro para mim quando a abordagem do kernel gaussiano density.psp()seria preferível à abordagem mais intuitiva de calcular diretamente os comprimentos de linha pixellate(). Acho que vou ter que deixar isso para os especialistas.

Matt SM
fonte