C'est une question difficile, car il n'y a pas eu beaucoup, s'il en est, de statistiques de processus spatiales développées pour les entités linéaires. Sans creuser sérieusement dans les équations et le code, les statistiques de processus ponctuelles ne sont pas facilement applicables aux entités linéaires et sont donc statistiquement non valides. En effet, le caractère NULL contre lequel un modèle donné est testé est basé sur des événements ponctuels et non sur des dépendances linéaires dans le champ aléatoire. Je dois dire que je ne sais même pas ce que le zéro serait en ce qui concerne l'intensité et l'arrangement / l'orientation serait encore plus difficile.
Je ne fais que cracher les pieds ici, mais je me demande si une évaluation à plusieurs échelles de la densité de lignes couplée à une distance euclidienne (ou une distance de Hausdorff si les lignes sont complexes) n'indiquerait pas une mesure continue du regroupement. Ces données pourraient ensuite être résumées en vecteurs de ligne, en utilisant la variance pour tenir compte de la disparité de longueurs (Thomas 2011), puis en attribuant une valeur de cluster à l'aide d'une statistique telle que K-moyennes. Je sais que vous ne recherchez pas les clusters mais la valeur de cluster peut partitionner les degrés de clustering. Cela nécessiterait évidemment un ajustement optimal de k, de sorte que des grappes arbitraires ne sont pas attribuées. Je pense que ce serait une approche intéressante pour évaluer la structure des contours dans les modèles théoriques de graphes.
Voici un exemple travaillé en R, désolé, mais il est plus rapide et plus reproductible que de fournir un exemple QGIS, et il est plus dans ma zone de confort :)
Ajouter des bibliothèques et utiliser un objet cuivre psp de spatstat comme exemple de ligne
library(spatstat)
library(raster)
library(spatialEco)
data(copper)
l <- copper$Lines
l <- rotate.psp(l, pi/2)
Calculer la densité de ligne normalisée des premier et deuxième ordres, puis contraindre les objets de la classe de trame
d1st <- density(l)
d1st <- d1st / max(d1st)
d1st <- raster(d1st)
d2nd <- density(l, sigma = 2)
d2nd <- d2nd / max(d2nd)
d2nd <- raster(d2nd)
Normaliser les densités des premier et deuxième ordres dans une densité intégrée à l'échelle
d <- d1st + d2nd
d <- d / cellStats(d, stat='max')
Calculer la distance euclidienne inversée normalisée et le contraindre à la classe de trame
euclidean <- distmap(l)
euclidean <- euclidean / max(euclidean)
euclidean <- raster.invert(raster(euclidean))
Contraint spatstat psp en un objet sp SpatialLinesDataFrame à utiliser dans 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)) )
Résultats de la parcelle
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)
Extraire des valeurs de raster et calculer des statistiques récapitulatives associées à chaque ligne
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)))
Utilisez les valeurs de silhouette de cluster pour évaluer k optimal (nombre de clusters), avec la fonction optimal.k, puis affectez des valeurs de cluster à des lignes. Nous pouvons ensuite affecter des couleurs à chaque cluster et tracer par-dessus le raster de densité.
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)
À ce stade, il est possible d'effectuer une randomisation des lignes pour vérifier si l'intensité et la distance résultantes sont significatives à partir de façon aléatoire. Vous pouvez utiliser la fonction "rshift.psp" pour réorienter vos lignes de manière aléatoire. Vous pouvez également simplement randomiser les points de début et de fin et recréer chaque ligne.
On peut également se demander "si" vous venez d'effectuer une analyse de configuration de points à l'aide d'une statistique d'analyse univariée ou croisée sur les points de début et de fin, invariants des lignes. Dans une analyse univariée, comparez les résultats des points de départ et d’arrêt pour vérifier s’il existe une cohérence dans la mise en cluster des modèles de deux points. Cela pourrait être fait via un f-hat, un G-hat ou un Ripley's-K-hat (pour les processus ponctuels non marqués). Une autre approche serait une analyse croisée (par exemple, cross-K) où les deux processus ponctuels sont testés simultanément en les marquant comme [start, stop]. Cela indiquerait les relations de distance dans le processus de regroupement entre les points de départ et d'arrêt. cependant, La dépendance spatiale (non staionarité) sur un processus d'intensité sous-jacent peut être un problème dans ces types de modèles, ce qui les rend non homogènes et nécessite un modèle différent. Ironiquement, le processus inhomogène est modélisé à l'aide d'une fonction d'intensité, ce qui nous ramène à la densité, ce qui conforte l'idée d'utiliser une densité intégrée à l'échelle comme mesure de la classification.
Voici un exemple rapide d'utilisation de la statistique Ripleys K (Besags L) pour l'autocorrélation d'un processus ponctuel non marqué à l'aide des emplacements de début et d'arrêt d'une classe d'entités linéaires. Le dernier modèle est un modèle croisé utilisant les emplacements de départ et d’arrêt en tant que processus marqué 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) ) )
Les références
Thomas JCR (2011) Un nouvel algorithme de clustering basé sur K-Means utilisant un segment de ligne comme prototype. Dans: San Martin C., Kim SW. (eds) Progrès en reconnaissance de formes, analyse d’images, vision par ordinateur et applications. CIARP 2011. Notes de cours en informatique, vol 7042. Springer, Berlin, Heidelberg