Bunu basit parçalara ayıralım. Bu şekilde, tüm işler sadece yarım düzine satırda kolayca test edilen kodda gerçekleştirilir.
İlk olarak, mesafeleri hesaplamanız gerekecektir. Veriler coğrafi koordinatlarda olduğundan, küresel bir veri üzerindeki mesafeleri hesaplamak için bir işlev (Haversine formülü kullanılarak):
#
# Spherical distance.
# `x` and `y` are (long, lat) pairs *in radians*.
dist <- function(x, y, R=1) {
d <- y - x
a <- sin(d[2]/2)^2 + cos(x[2])*cos(y[2])*sin(d[1]/2)^2
return (R * 2*atan2(sqrt(a), sqrt(1-a)))
}
İsterseniz bunu en sevdiğiniz uygulama ile değiştirin (elipsoidal datum kullanan bir uygulama gibi).
Daha sonra, her "temel nokta" (staionarite için kontrol ediliyor) ve geçici komşuları arasındaki mesafeleri hesaplamamız gerekecek. Bu sadece dist
mahalleye başvurma meselesi :
#
# Compute the distances between an array of locations and a base location `x`.
dist.array <- function(a, x, ...) apply(a, 1, function(y) dist(x, y, ...))
Üçüncüsü - bu anahtar fikirdir - durağan noktalar, mesafeleri yeterince küçük olan arka arkaya en az beş olan 11 noktanın mahallelerini tespit ederek bulunur. Mantıksal bir boole değerleri dizisindeki gerçek değerlerin en uzun dizisinin uzunluğunu belirleyerek bunu biraz daha genel olarak uygulayalım:
#
# Return the length of the longest sequence of true values in `x`.
max.subsequence <- function(x) max(diff(c(0, which(!x), length(x)+1)))
( Yanlış değerlerin konumlarını sırayla buluruz ve farklılıklarını hesaplarız: bunlar yanlış olmayan değerlerin alt dizileridir. Bu en büyük uzunluk döndürülür.)
Dördüncüsü, max.subsequence
durağan noktaları tespit etmek için başvuruyoruz .
#
# Determine whether a point `x` is "stationary" relative to a sequence of its
# neighbors `a`. It is provided there is a sequence of at least `k`
# points in `a` within distance `radius` of `x`, where the earth's radius is
# set to `R`.
is.stationary <- function(x, a, k=floor(length(a)/2), radius=100, R=6378.137)
max.subsequence(dist.array(a, x, R) <= radius) >= k
Bunlar ihtiyacımız olan aletler.
Örnek olarak, birkaç durağan nokta kümesine sahip bazı ilginç veriler oluşturalım. Ekvator'un yakınında rastgele bir yürüyüş yapacağım.
set.seed(17)
n <- 67
theta <- 0:(n-1) / 50 - 1 + rnorm(n, sd=1/2)
rho <- rgamma(n, 2, scale=1/2) * (1 + cos(1:n / n * 6 * pi))
lon <- cumsum(cos(theta) * rho); lat <- cumsum(sin(theta) * rho)
Dizileri sırayla nokta cinsinden sıralar lon
ve lat
koordinatları içerir n
. İlk olarak radyana dönüştükten sonra araçlarımızı uygulamak basittir:
p <- cbind(lon, lat) * pi / 180 # Convert from degrees to radians
p.stationary <- sapply(1:n, function(i)
is.stationary(p[i,], p[max(1,i-5):min(n,i+5), ], k=5))
Argüman p[max(1,i-5):min(n,i+5), ]
taban noktasından 5 zaman adımına veya 5 zaman adımına kadar ileriye baktığını söylüyor p[i,]
. Dahil etme k=5
, taban noktasının 100 km'sinde olan bir sırada 5 veya daha fazla bir sıra aradığını söylüyor. (100 km değeri varsayılan olarak ayarlandı, is.stationary
ancak burada geçersiz kılabilirsiniz.)
Çıktı p.stationary
durağanlığı gösteren mantıklı bir vektördür: bizim için ne geldiğimize sahibiz. Ancak, prosedürü kontrol etmek için değer dizilerini incelemek yerine verileri ve bu sonuçları çizmek en iyisidir. Aşağıdaki grafikte rotayı ve puanları göstereceğim. Her onuncu nokta etiketlidir, böylece sabit kümeler içinde kaç kişinin çakışabileceğini tahmin edebilirsiniz. Sabit noktalar, onları vurgulamak için düz kırmızı renkte yeniden çizilir ve 100 km'lik tamponlarıyla çevrelenir.
plot(p, type="l", asp=1, col="Gray",
xlab="Longitude (radians)", ylab="Latitude (radians)")
points(p)
points(p[p.stationary, ], pch=19, col="Red", cex=0.75)
i <- seq(1, n, by=10)
#
# Because we're near the Equator in this example, buffers will be nearly
# circular: approximate them.
disk <- function(x, r, n=32) {
theta <- 1:n / n * 2 * pi
return (t(rbind(cos(theta), sin(theta))*r + x))
}
r <- 100 / 6378.137 # Buffer radius in radians
apply(p[p.stationary, ], 1, function(x)
invisible(polygon(disk(x, r), col="#ff000008", border="#00000040")))
text(p[i,], labels=paste(i), pos=3, offset=1.25, col="Gray")
Çalışma kodu da dahil olmak üzere, izlenen verilerde durağan noktalar bulmak için diğer (istatistiksel temelli) yaklaşımlar için lütfen /mathematica/2711/clustering-of-space-time-data adresini ziyaret edin .