Hãy chia nó thành những mảnh đơn giản. Bằng cách làm như vậy, tất cả các công việc được hoàn thành chỉ trong nửa tá dòng mã được kiểm tra dễ dàng.
Đầu tiên, bạn sẽ cần tính khoảng cách. Vì dữ liệu nằm trong tọa độ địa lý, đây là một hàm để tính khoảng cách trên mốc dữ liệu hình cầu (sử dụng công thức 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)))
}
Thay thế điều này bằng cách thực hiện yêu thích của bạn nếu bạn muốn (chẳng hạn như sử dụng một mốc thời gian hình elip).
Tiếp theo, chúng ta sẽ cần tính khoảng cách giữa mỗi "điểm gốc" (đang được kiểm tra tính ổn định) và vùng lân cận tạm thời của nó. Đó đơn giản chỉ là vấn đề áp dụng dist
cho khu phố:
#
# 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, ...))
Thứ ba - đây là ý tưởng chính - các điểm dừng được tìm thấy bằng cách phát hiện các vùng lân cận 11 điểm có ít nhất năm điểm liên tiếp có khoảng cách đủ nhỏ. Chúng ta hãy thực hiện điều này một chút chung hơn bằng cách xác định độ dài của chuỗi giá trị thực dài nhất trong một mảng logic của các giá trị boolean:
#
# 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)))
(Chúng tôi tìm vị trí của các giá trị sai , theo thứ tự và tính toán sự khác biệt của chúng: đây là độ dài của các giá trị không sai. Độ dài lớn nhất được trả về.)
Thứ tư, chúng tôi áp dụng max.subsequence
để phát hiện các điểm dừng.
#
# 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
Đó là tất cả các công cụ chúng ta cần.
Ví dụ, hãy tạo một số dữ liệu thú vị có một vài điểm dừng. Tôi sẽ đi bộ ngẫu nhiên gần Xích đạo.
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)
Các mảng lon
và lat
chứa tọa độ, tính bằng độ, của các n
điểm theo thứ tự. Áp dụng các công cụ của chúng tôi rất đơn giản sau lần đầu tiên chuyển đổi thành radian:
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))
Đối số p[max(1,i-5):min(n,i+5), ]
nói rằng hãy nhìn xa tới 5 bước thời gian hoặc tiến xa tới 5 bước thời gian từ điểm gốc p[i,]
. Bao gồm k=5
nói để tìm kiếm một chuỗi từ 5 trở lên liên tiếp trong phạm vi 100 km từ điểm cơ sở. (Giá trị 100 km được đặt làm mặc định is.stationary
nhưng bạn có thể ghi đè lên đây.)
Đầu ra p.stationary
là một vectơ logic biểu thị sự ổn định: chúng ta có những gì chúng ta đã đến. Tuy nhiên, để kiểm tra quy trình, tốt nhất là vẽ sơ đồ dữ liệu và các kết quả này thay vì kiểm tra các mảng giá trị. Trên sơ đồ sau tôi chỉ ra tuyến đường và các điểm. Mỗi điểm thứ mười được dán nhãn để bạn có thể ước tính có bao nhiêu điểm có thể trùng lặp trong các cụm đứng yên. Các điểm dừng được vẽ lại bằng màu đỏ đặc để làm nổi bật chúng và được bao quanh bởi bộ đệm 100 km của chúng.
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")
Đối với các cách tiếp cận khác (dựa trên thống kê) để tìm các điểm dừng trong dữ liệu được theo dõi, bao gồm cả mã làm việc, vui lòng truy cập https://mathIALa.stackexchange.com/questions/2711/clustering-of-space-time-data .