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.

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.