Đưa ra một danh sách các vị trí điểm (tốt nhất là trong tọa độ dự kiến, để khoảng cách dễ tính toán), vấn đề này có thể được giải quyết bằng năm thao tác đơn giản hơn :
Tính khoảng cách điểm-điểm.
Đối với mỗi điểm i, i = 1, 2, ..., hãy xác định các chỉ mục của các điểm đó ở khoảng cách nhỏ hơn bán kính bộ đệm (chẳng hạn như 1500).
Hạn chế các chỉ số là i hoặc lớn hơn.
Chỉ giữ lại nhóm chỉ số liên tiếp đầu tiên không nghỉ.
Xuất số đếm của nhóm đó.
Trong R
, mỗi trong số này tương ứng với một hoạt động. Để áp dụng trình tự này cho từng điểm, thật thuận tiện để đóng gói hầu hết các công việc trong một chức năng mà chúng tôi xác định , do đó:
#
# 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)))
}
(Xem bên dưới để biết phiên bản hiệu quả hơn của chức năng này.)
Tôi đã làm cho hàm này đủ linh hoạt để chấp nhận các danh sách điểm khác nhau ( xy
) và khoảng cách bộ đệm ( r
) làm tham số.
Thông thường, bạn sẽ đọc một tệp các vị trí điểm (và, nếu cần, sắp xếp chúng theo thời gian). Ở đây, để thể hiện điều này trong thực tế, chúng tôi sẽ chỉ tạo ngẫu nhiên một số dữ liệu mẫu :
# 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")
Khoảng cách thông thường của chúng là 300 * Sqrt (2) = khoảng 500. Chúng tôi thực hiện phép tính bằng cách áp dụng hàm này cho các điểm trong mảngxy
(và sau đó xử lý kết quả của nó trở lại xy
, bởi vì đây sẽ là định dạng thuận tiện để xuất sang GIS ):
radius <- 1500
z <- sapply(1:n, function(u){forward(u,xy,radius)})
result <- cbind(xy, z) # List of points, counts
Sau đó, bạn sẽ phân tích thêm result
mảng, bằng R
hoặc bằng cách ghi nó vào một tệp và nhập nó vào phần mềm khác. Đây là kết quả cho dữ liệu mẫu :
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
(Hãy nhớ rằng các số đếm bao gồm các điểm mà chúng dựa vào, sao cho mỗi số phải là 1 hoặc lớn hơn.)
Nếu bạn có nhiều nghìn điểm, phương pháp này quá kém hiệu quả : nó tính toán quá nhiều khoảng cách điểm-điểm không cần thiết. Nhưng bởi vì chúng tôi đã gói gọn công việc trong forward
hàm, nên tính không hiệu quả rất dễ khắc phục. Đây là một phiên bản sẽ hoạt động tốt hơn khi có hơn vài trăm điểm:
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
}
Để kiểm tra điều này, tôi đã tạo các điểm ngẫu nhiên như trước đây nhưng thay đổi hai tham số: n
(số lượng điểm) và độ lệch chuẩn của chúng (mã hóa cứng là 300 ở trên). Độ lệch chuẩn xác định số điểm trung bình trong mỗi bộ đệm ("trung bình" trong bảng bên dưới): càng có nhiều, thuật toán này càng mất nhiều thời gian để chạy. (Với các thuật toán phức tạp hơn, thời gian chạy sẽ không phụ thuộc nhiều vào số lượng điểm trong mỗi bộ đệm.) Dưới đây là một số thời gian:
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