Tôi thấy MerseyViking đã đề xuất một phần tư . Tôi sẽ đề xuất điều tương tự và để giải thích nó, đây là mã và một ví dụ. Mã được viết bằng R
nhưng phải chuyển dễ dàng sang Python.
Ý tưởng rất đơn giản: chia các điểm xấp xỉ một nửa theo hướng x, sau đó phân chia đệ quy hai nửa dọc theo hướng y, xen kẽ các hướng ở mỗi cấp độ, cho đến khi không muốn tách nữa.
Vì mục đích là ngụy trang các vị trí điểm thực tế, nên rất hữu ích khi đưa một số ngẫu nhiên vào các phần tách . Một cách đơn giản nhanh chóng để làm điều này là phân chia ở mức định lượng đặt một lượng ngẫu nhiên nhỏ cách xa 50%. Theo cách này (a) các giá trị phân tách rất khó trùng khớp với tọa độ dữ liệu, do đó các điểm sẽ rơi vào các góc phần tư được tạo bởi phân vùng và (b) tọa độ điểm sẽ không thể tái tạo chính xác từ góc phần tư.
Vì ý định là duy trì số lượng k
nút tối thiểu trong mỗi lá tứ giác, chúng tôi thực hiện một hình thức hạn chế của tứ giác. Nó sẽ hỗ trợ (1) các điểm phân cụm thành các nhóm có giữa k
và 2 * k
-1 phần tử mỗi và (2) ánh xạ các góc phần tư.
R
Mã này tạo ra một cây các nút và các lá cuối, phân biệt chúng theo lớp. Việc ghi nhãn lớp nhanh chóng xử lý hậu kỳ như âm mưu, được hiển thị bên dưới. Mã sử dụng các giá trị số cho các id. Điều này hoạt động đến độ sâu 52 trong cây (sử dụng gấp đôi; nếu sử dụng số nguyên dài không dấu, độ sâu tối đa là 32). Đối với các cây sâu hơn (rất khó xảy ra trong bất kỳ ứng dụng nào, vì ít nhất k
* 2 ^ 52 điểm sẽ được tham gia), id sẽ phải là chuỗi.
quadtree <- function(xy, k=1) {
d = dim(xy)[2]
quad <- function(xy, i, id=1) {
if (length(xy) < 2*k*d) {
rv = list(id=id, value=xy)
class(rv) <- "quadtree.leaf"
}
else {
q0 <- (1 + runif(1,min=-1/2,max=1/2)/dim(xy)[1])/2 # Random quantile near the median
x0 <- quantile(xy[,i], q0)
j <- i %% d + 1 # (Works for octrees, too...)
rv <- list(index=i, threshold=x0,
lower=quad(xy[xy[,i] <= x0, ], j, id*2),
upper=quad(xy[xy[,i] > x0, ], j, id*2+1))
class(rv) <- "quadtree"
}
return(rv)
}
quad(xy, 1)
}
Lưu ý rằng thiết kế phân chia và chinh phục đệ quy của thuật toán này (và do đó, trong hầu hết các thuật toán xử lý hậu kỳ) có nghĩa là yêu cầu về thời gian là O (m) và mức sử dụng RAM là O (n) trong đó m
số các ô và n
là số điểm. m
tỷ lệ với n
chia cho các điểm tối thiểu trên mỗi ô,k
. Điều này rất hữu ích để ước tính thời gian tính toán. Chẳng hạn, nếu mất 13 giây để phân vùng n = 10 ^ 6 điểm vào các ô 50-99 điểm (k = 50), m = 10 ^ 6/50 = 20000. Thay vào đó, nếu bạn muốn phân vùng xuống 5-9 điểm trên mỗi ô (k = 5), m lớn hơn 10 lần, do đó thời gian tăng lên khoảng 130 giây. (Vì quá trình phân chia một tập hợp tọa độ xung quanh các câu đố của chúng sẽ nhanh hơn khi các ô nhỏ hơn, thời gian thực tế chỉ là 90 giây.) Để đi hết quãng đường tới k = 1 điểm trên mỗi ô, sẽ mất khoảng sáu lần Tuy nhiên, hoặc chín phút, và chúng ta có thể mong đợi mã thực sự nhanh hơn một chút so với.
Trước khi đi xa hơn, hãy tạo ra một số dữ liệu cách đều đặn thú vị và tạo ra tứ giác bị hạn chế của chúng (thời gian trôi qua 0,29 giây):
Đây là mã để sản xuất các lô này. Nó khai thác R
tính đa hình của nó: points.quadtree
sẽ được gọi bất cứ khi nào points
hàm được áp dụng cho một quadtree
đối tượng. Sức mạnh của điều này thể hiện rõ ở sự cực kỳ đơn giản của hàm để tô màu các điểm theo định danh cụm của chúng:
points.quadtree <- function(q, ...) {
points(q$lower, ...); points(q$upper, ...)
}
points.quadtree.leaf <- function(q, ...) {
points(q$value, col=hsv(q$id), ...)
}
Việc tự vẽ lưới là khó khăn hơn một chút vì nó đòi hỏi phải lặp đi lặp lại các ngưỡng được sử dụng cho phân vùng bốn góc, nhưng cách tiếp cận đệ quy tương tự là đơn giản và thanh lịch. Sử dụng một biến thể để xây dựng các biểu diễn đa giác của góc phần tư nếu muốn.
lines.quadtree <- function(q, xylim, ...) {
i <- q$index
j <- 3 - q$index
clip <- function(xylim.clip, i, upper) {
if (upper) xylim.clip[1, i] <- max(q$threshold, xylim.clip[1,i]) else
xylim.clip[2,i] <- min(q$threshold, xylim.clip[2,i])
xylim.clip
}
if(q$threshold > xylim[1,i]) lines(q$lower, clip(xylim, i, FALSE), ...)
if(q$threshold < xylim[2,i]) lines(q$upper, clip(xylim, i, TRUE), ...)
xlim <- xylim[, j]
xy <- cbind(c(q$threshold, q$threshold), xlim)
lines(xy[, order(i:j)], ...)
}
lines.quadtree.leaf <- function(q, xylim, ...) {} # Nothing to do at leaves!
Một ví dụ khác, tôi đã tạo ra 1.000.000 điểm và phân chia chúng thành các nhóm 5-9 mỗi điểm. Thời gian là 91,7 giây.
n <- 25000 # Points per cluster
n.centers <- 40 # Number of cluster centers
sd <- 1/2 # Standard deviation of each cluster
set.seed(17)
centers <- matrix(runif(n.centers*2, min=c(-90, 30), max=c(-75, 40)), ncol=2, byrow=TRUE)
xy <- matrix(apply(centers, 1, function(x) rnorm(n*2, mean=x, sd=sd)), ncol=2, byrow=TRUE)
k <- 5
system.time(qt <- quadtree(xy, k))
#
# Set up to map the full extent of the quadtree.
#
xylim <- cbind(x=c(min(xy[,1]), max(xy[,1])), y=c(min(xy[,2]), max(xy[,2])))
plot(xylim, type="n", xlab="x", ylab="y", main="Quadtree")
#
# This is all the code needed for the plot!
#
lines(qt, xylim, col="Gray")
points(qt, pch=".")
Như một ví dụ về cách tương tác với một hệ thống GIS , chúng ta hãy viết ra tất cả các ô tứ giác dưới dạng một hình đa giác bằng shapefiles
thư viện. Mã mô phỏng các thói quen cắt của lines.quadtree
, nhưng lần này nó phải tạo ra các mô tả vector của các ô. Đây là những đầu ra dưới dạng khung dữ liệu để sử dụng với shapefiles
thư viện.
cell <- function(q, xylim, ...) {
if (class(q)=="quadtree") f <- cell.quadtree else f <- cell.quadtree.leaf
f(q, xylim, ...)
}
cell.quadtree <- function(q, xylim, ...) {
i <- q$index
j <- 3 - q$index
clip <- function(xylim.clip, i, upper) {
if (upper) xylim.clip[1, i] <- max(q$threshold, xylim.clip[1,i]) else
xylim.clip[2,i] <- min(q$threshold, xylim.clip[2,i])
xylim.clip
}
d <- data.frame(id=NULL, x=NULL, y=NULL)
if(q$threshold > xylim[1,i]) d <- cell(q$lower, clip(xylim, i, FALSE), ...)
if(q$threshold < xylim[2,i]) d <- rbind(d, cell(q$upper, clip(xylim, i, TRUE), ...))
d
}
cell.quadtree.leaf <- function(q, xylim) {
data.frame(id = q$id,
x = c(xylim[1,1], xylim[2,1], xylim[2,1], xylim[1,1], xylim[1,1]),
y = c(xylim[1,2], xylim[1,2], xylim[2,2], xylim[2,2], xylim[1,2]))
}
Các điểm có thể được đọc trực tiếp bằng cách sử dụng read.shp
hoặc bằng cách nhập tệp dữ liệu có tọa độ (x, y).
Ví dụ sử dụng:
qt <- quadtree(xy, k)
xylim <- cbind(x=c(min(xy[,1]), max(xy[,1])), y=c(min(xy[,2]), max(xy[,2])))
polys <- cell(qt, xylim)
polys.attr <- data.frame(id=unique(polys$id))
library(shapefiles)
polys.shapefile <- convert.to.shapefile(polys, polys.attr, "id", 5)
write.shapefile(polys.shapefile, "f:/temp/quadtree", arcgis=TRUE)
(Sử dụng bất kỳ phạm vi mong muốn nào xylim
ở đây để cửa sổ vào một tiểu vùng hoặc để mở rộng ánh xạ tới một khu vực lớn hơn; mã này mặc định theo phạm vi của các điểm.)
Điều này là đủ: một liên kết không gian của các đa giác với các điểm ban đầu sẽ xác định các cụm. Sau khi xác định, các hoạt động "tóm tắt" cơ sở dữ liệu sẽ tạo ra số liệu thống kê tóm tắt về các điểm trong mỗi ô.