Essa é uma pergunta difícil, pois simplesmente não existem muitas estatísticas de processo espacial, se houver alguma, desenvolvidas para recursos de linha. Sem investigar seriamente as equações e o código, as estatísticas do processo pontual não são prontamente aplicáveis a recursos lineares e, portanto, estatisticamente inválidas. Isso ocorre porque o nulo, contra o qual um determinado padrão é testado, é baseado em eventos pontuais e não em dependências lineares no campo aleatório. Devo dizer que nem sei qual seria o nulo na medida em que intensidade e arranjo / orientação seriam ainda mais difíceis.
Estou apenas cuspindo aqui, mas estou imaginando se uma avaliação em escala múltipla da densidade da linha acoplada à distância euclidiana (ou distância de Hausdorff se as linhas forem complexas) não indicaria uma medida contínua de agrupamento. Esses dados podem então ser resumidos aos vetores de linha, usando a variação para explicar a disparidade nos comprimentos (Thomas 2011), e atribuídos um valor de cluster usando uma estatística como K-means. Eu sei que você não está atrás de clusters atribuídos, mas o valor do cluster pode particionar graus de cluster. Obviamente, isso exigiria um ajuste ideal de k, portanto, clusters arbitrários não são atribuídos. Estou pensando que essa seria uma abordagem interessante na avaliação da estrutura de arestas em modelos teóricos de gráficos.
Aqui está um exemplo trabalhado em R, desculpe, mas é mais rápido e mais reproduzível do que fornecer um exemplo QGIS, e está mais na minha zona de conforto :)
Adicione bibliotecas e use o objeto psp de cobre do spatstat como exemplo de linha
library(spatstat)
library(raster)
library(spatialEco)
data(copper)
l <- copper$Lines
l <- rotate.psp(l, pi/2)
Calcular a densidade de linha padronizada de 1ª e 2ª ordem e coagir a objetos de classe raster
d1st <- density(l)
d1st <- d1st / max(d1st)
d1st <- raster(d1st)
d2nd <- density(l, sigma = 2)
d2nd <- d2nd / max(d2nd)
d2nd <- raster(d2nd)
Padronize a densidade de 1ª e 2ª ordem em uma densidade integrada na balança
d <- d1st + d2nd
d <- d / cellStats(d, stat='max')
Calcular a distância euclidiana invertida padronizada e coagir à classe raster
euclidean <- distmap(l)
euclidean <- euclidean / max(euclidean)
euclidean <- raster.invert(raster(euclidean))
Coerce o spatstat psp para um objeto SpatialLinesDataFrame para usar no raster :: extract
as.SpatialLines.psp <- local({
ends2line <- function(x) Line(matrix(x, ncol=2, byrow=TRUE))
munch <- function(z) { Lines(ends2line(as.numeric(z[1:4])), ID=z[5]) }
convert <- function(x) {
ends <- as.data.frame(x)[,1:4]
ends[,5] <- row.names(ends)
y <- apply(ends, 1, munch)
SpatialLines(y)
}
convert
})
l <- as.SpatialLines.psp(l)
l <- SpatialLinesDataFrame(l, data.frame(ID=1:length(l)) )
Resultados do gráfico
par(mfrow=c(2,2))
plot(d1st, main="1st order line density")
plot(l, add=TRUE)
plot(d2nd, main="2nd order line density")
plot(l, add=TRUE)
plot(d, main="integrated line density")
plot(l, add=TRUE)
plot(euclidean, main="euclidean distance")
plot(l, add=TRUE)
Extraia valores de varredura e calcule estatísticas resumidas associadas a cada linha
l.dist <- extract(euclidean, l)
l.den <- extract(d, l)
l.stats <- data.frame(min.dist = unlist(lapply(l.dist, min)),
med.dist = unlist(lapply(l.dist, median)),
max.dist = unlist(lapply(l.dist, max)),
var.dist = unlist(lapply(l.dist, var)),
min.den = unlist(lapply(l.den, min)),
med.den = unlist(lapply(l.den, median)),
max.den = unlist(lapply(l.den, max)),
var.den = unlist(lapply(l.den, var)))
Use valores de silhueta de cluster para avaliar k ideal (número de clusters), com a função ideal.k, depois atribua valores de cluster a linhas. Podemos então atribuir cores a cada cluster e plotar em cima da varredura de densidade.
clust <- optimal.k(scale(l.stats), nk = 10, plot = TRUE)
l@data <- data.frame(l@data, cluster = clust$clustering)
kcol <- ifelse(clust$clustering == 1, "red", "blue")
plot(d)
plot(l, col=kcol, add=TRUE)
Nesse ponto, pode-se realizar uma randomização das linhas para testar se a intensidade e a distância resultantes são significativas em relação ao aleatório. Você pode usar a função "rshift.psp" para reorientar suas linhas aleatoriamente. Você também pode randomizar os pontos de início e parada e recriar cada linha.
Também se pergunta "e se" você acabou de executar uma análise de padrão de pontos usando uma estatística de análise cruzada ou univariada nos pontos de partida e parada, invariáveis nas linhas. Em uma análise univariada, você compararia os resultados dos pontos inicial e final para verificar se há consistência no agrupamento entre os dois padrões de pontos. Isso pode ser feito via f-hat, G-hat ou Ripley's-K-hat (para processos pontuais não marcados). Outra abordagem seria uma análise cruzada (por exemplo, cross-K), na qual os dois processos pontuais são testados simultaneamente, marcando-os como [iniciar, parar]. Isso indicaria as relações de distância no processo de armazenamento em cluster entre os pontos de partida e parada. Contudo, a dependência espacial (não estacionalidade) de um processo de intensidade subjacente pode ser um problema nesses tipos de modelos, tornando-os não homogêneos e exigindo um modelo diferente. Ironicamente, o processo não homogêneo é modelado usando uma função de intensidade que nos leva a um círculo completo de volta à densidade, apoiando a idéia de usar uma densidade integrada na balança como uma medida de agrupamento.
Aqui está um exemplo rápido de se a estatística Ripleys K (Besags L) para autocorrelação de um processo de ponto não marcado usando o início, para locais de uma classe de recurso de linha. O último modelo é um cruzamento usando os locais de partida e parada como um processo marcado nominal.
library(spatstat)
data(copper)
l <- copper$Lines
l <- rotate.psp(l, pi/2)
Lr <- function (...) {
K <- Kest(...)
nama <- colnames(K)
K <- K[, !(nama %in% c("rip", "ls"))]
L <- eval.fv(sqrt(K/pi)-bw)
L <- rebadge.fv(L, substitute(L(r), NULL), "L")
return(L)
}
### Ripley's K ( Besag L(r) ) for start locations
start <- endpoints.psp(l, which="first")
marks(start) <- factor("start")
W <- start$window
area <- area.owin(W)
lambda <- start$n / area
ripley <- min(diff(W$xrange), diff(W$yrange))/4
rlarge <- sqrt(1000/(pi * lambda))
rmax <- min(rlarge, ripley)
( Lenv <- plot( envelope(start, fun="Lr", r=seq(0, rmax, by=1), nsim=199, nrank=5) ) )
### Ripley's K ( Besag L(r) ) for end locations
stop <- endpoints.psp(l, which="second")
marks(stop) <- factor("stop")
W <- stop$window
area <- area.owin(W)
lambda <- stop$n / area
ripley <- min(diff(W$xrange), diff(W$yrange))/4
rlarge <- sqrt(1000/(pi * lambda))
rmax <- min(rlarge, ripley)
( Lenv <- plot( envelope(start, fun="Lr", r=seq(0, rmax, by=1), nsim=199, nrank=5) ) )
### Ripley's Cross-K ( Besag L(r) ) for start/stop
sdata.ppp <- superimpose(start, stop)
( Lenv <- plot(envelope(sdata.ppp, fun="Kcross", r=bw, i="start", j="stop", nsim=199,nrank=5,
transform=expression(sqrt(./pi)-bw), global=TRUE) ) )
Referências
Thomas JCR (2011) Um novo algoritmo de agrupamento baseado em meios K usando um segmento de linha como protótipo. In: San Martin C., Kim SW. (eds) Progresso no reconhecimento de padrões, análise de imagens, visão computacional e aplicativos. CIARP 2011. Notas de aula em Ciência da Computação, vol 7042. Springer, Berlim, Heidelberg