これを簡単な部分に分解してみましょう。そうすることで、すべての作業は簡単にテストできるわずか数行のコードで実行されます。
まず、距離を計算する必要があります。データは地理座標系にあるため、球面データムの距離を計算する関数があります(Haversine式を使用):
#
# 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)))
}
必要に応じて、これをお好みの実装(楕円体データムを使用するものなど)に置き換えます。
次に、各「基点」(定常性がチェックされている)とその時間的近傍の間の距離を計算する必要があります。それは単にdist
近所に適用することの問題です:
#
# 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, ...))
3つ目は、これが重要なアイデアです。静止した点は、距離が十分に小さい行に少なくとも5つある11個の点の近傍を検出することで見つかります。ブール値の論理配列内の真の値の最も長いサブシーケンスの長さを決定することにより、これをもう少し一般的に実装してみましょう。
#
# 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)))
(誤った値の場所を順番に見つけて、それらの違いを計算します。これらは、誤った値ではないサブシーケンスの長さです。そのような最大の長さが返されます。)
第4に、max.subsequence
静止点の検出に適用します。
#
# 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
これらは私たちが必要とするすべてのツールです。
例として、いくつかの静止点の集まりを持つ興味深いデータを作成してみましょう。赤道近くを散歩します。
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)
配列lon
にlat
は、n
順番にポイントの座標が度数で含まれます。最初にラジアンに変換した後、ツールを適用するのは簡単です。
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))
議論p[max(1,i-5):min(n,i+5), ]
は、基点から5タイムステップまでさかのぼって、または5タイムステップまでさかのぼって見るように言っていますp[i,]
。含むk=5
と、基点から100 km以内にある5つ以上のシーケンスを連続して検索します。(デフォルトでは100 kmの値が設定されてis.stationary
いますが、ここでオーバーライドできます。)
出力p.stationary
は、定常性を示す論理ベクトルです。ただし、手順を確認するには、値の配列を検査するのではなく、データとこれらの結果をプロットするのが最善です。次のプロットでは、ルートとポイントを示しています。10個ごとのポイントにラベルが付けられるので、静止した束内で重複する可能性のある数を推定できます。静止ポイントは赤く塗りつぶされて強調表示され、100 kmのバッファーで囲まれます。
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")
作業コードを含む、追跡されたデータで静止点を見つける他の(統計ベースの)アプローチについては、https://mathematica.stackexchange.com/questions/2711/clustering-of-space-time-dataにアクセスしてください。