Bei einer Liste von Punktpositionen (vorzugsweise in projizierten Koordinaten, damit Entfernungen leicht berechnet werden können) kann dieses Problem mit fünf einfacheren Operationen gelöst werden :
Berechnen Sie Punkt-Punkt-Abstände.
Identifizieren Sie für jeden Punkt i, i = 1, 2, ... die Indizes dieser Punkte in Abständen, die kleiner als der Pufferradius sind (z. B. 1500).
Beschränken Sie diese Indizes auf i oder höher.
Behalten Sie nur die erste aufeinanderfolgende Gruppe von Indizes bei, die keine Unterbrechung aufweisen.
Geben Sie die Anzahl dieser Gruppe aus.
In entspricht R
jede dieser Operationen einer Operation. Um gelten für jeden Punkt dieser Sequenz ist es bequem, die meisten der Arbeit innerhalb einer Funktion kapseln wir definieren , also:
#
# forward(j, xy, r) counts how many contiguous rows in array xy, starting at index j,
# are within (Euclidean) distance r of the jth row of xy.
#
forward <- function(j, xy, r) {
# Steps 1 and 2: compute an array of indexes of points within distance r of point j.
i <- which(apply(xy, 1, function(x){sum((x-xy[j,])^2) <= r^2}))
# Step 3: select only the indexes at or after j.
i <- i[i >= j]
# Steps 4 and 5: retain only the first consecutive group and count it.
length(which(i <= (1:length(i) + j)))
}
(Eine effizientere Version dieser Funktion finden Sie weiter unten.)
Ich habe diese Funktion flexibel genug gemacht, um verschiedene Punktlisten ( xy
) und Pufferabstände ( r
) als Parameter zu akzeptieren .
Normalerweise lesen Sie eine Datei mit Punktpositionen (und sortieren Sie sie gegebenenfalls nach Zeit). Um dies in Aktion zu zeigen, werden wir nur einige Beispieldaten zufällig generieren :
# Create sample data
n<-16 # Number of points
set.seed(17) # For reproducibility
xy <- matrix(rnorm(2*n) + 1:n, n, 2) * 300
#
# Display the track.
plot(xy, xlab="x", ylab="y")
lines(xy, col="Gray")
Ihr typischer Abstand beträgt 300 * Sqrt (2) = ungefähr 500. Wir führen die Berechnung durch, indem wir diese Funktion auf die Punkte im Array anwendenxy
(und dann die Ergebnisse wieder anheften xy
, da dies ein praktisches Format für den Export in ein GIS wäre ):
radius <- 1500
z <- sapply(1:n, function(u){forward(u,xy,radius)})
result <- cbind(xy, z) # List of points, counts
Anschließend analysieren Sie das result
Array weiter, R
indem Sie es entweder in eine Datei schreiben oder in eine andere Software importieren. Hier ist das Ergebnis für die Beispieldaten :
z
[1,] -4.502615 551.5413 4
[2,] 576.108979 647.8110 3
[3,] 830.103893 1087.7863 4
[4,] 954.819620 1390.0754 3
...
[15,] 4977.361529 4146.7291 2
[16,] 4783.446283 4511.9500 1
(Denken Sie daran , dass die Zählungen sind die Punkte , an denen sie basieren, so dass jede Zählung 1 oder größer sein müssen.)
Wenn Sie viele tausend Punkte haben, ist diese Methode zu ineffizient : Sie berechnet viel zu viele unnötige Punkt-zu-Punkt-Abstände. Da wir jedoch die Arbeit in die forward
Funktion eingekapselt haben , lässt sich die Ineffizienz leicht beheben. Hier ist eine Version, die besser funktioniert, wenn mehr als ein paar hundert Punkte beteiligt sind:
forward <- function(j, xy, r) {
n <- dim(xy)[1] # Limit the search to the number of points in xy
r2 <- r^2 # Pre-compute the squared distance threshold
z <- xy[j,] # Pre-fetch the base point coordinates
i <- j+1 # Initialize an index into xy (just past point j)
# Advance i while point i remains within distance r of point j.
while(i <= n && sum((xy[i,]-z)^2) <= r2) i <- i+1
# Return the count (including point j).
i-j
}
Um dies zu testen, habe ich wie zuvor zufällige Punkte erstellt, aber zwei Parameter variiert: n
(die Anzahl der Punkte) und ihre Standardabweichung (oben als 300 fest codiert). Die Standardabweichung bestimmt die durchschnittliche Anzahl von Punkten in jedem Puffer ("Durchschnitt" in der folgenden Tabelle): Je mehr Punkte vorhanden sind, desto länger dauert die Ausführung dieses Algorithmus. (Bei komplexeren Algorithmen hängt die Laufzeit nicht so stark davon ab, wie viele Punkte sich in jedem Puffer befinden.) Hier einige Zeitpunkte:
Time (sec) n SD Average Distances checked per minute
1.30 10^3 3 291 13.4 million
1.72 10^4 30 35.7 12.5
2.50 10^5 300 3.79 9.1
16.4 10^6 3000 1.04 3.8