Görüyorum MerseyViking bir dörtlü tavsiye etti . Aynı şeyi önerecektim ve açıklamak için kod ve bir örnek. Kod yazılmıştır, R
ancak Python'a kolayca bağlanmalıdır.
Fikir son derece basittir: noktaları x yönünde yaklaşık ikiye bölün, sonra iki yarıyı y-yönü boyunca, her seviyede alternatif yönler olacak şekilde, daha fazla bölme istenmeyene kadar bölün.
Amaç, gerçek nokta konumlarını gizlemek olduğundan, bölünmelere biraz rastgelelik kazandırmak yararlıdır . Bunu yapmanın hızlı basit bir yolu,% 50'den küçük bir rastgele miktar ayarlamak için bir kantil olarak bölmektir. Bu şekilde (a) bölme değerlerinin veri koordinatlarına denk gelmesi pek olası değildir, böylece noktalar, bölümleme tarafından oluşturulan çeyreklere ayrılacaktır ve (b) nokta koordinatlarının, dördüncülden tam olarak yeniden yapılandırılması imkansız olacaktır.
Amaç, k
her dörtlü yaprak içinde minimum miktarda düğüm sağlamak olduğundan, sınırlı bir dörtlü form uygularız. (1) kümelenme noktalarını, her biri ve k
2 * k
-1 elemente sahip gruplara ve (2) kadranları eşleştirmeye destekleyecektir.
Bu R
kod, düğümleri ve terminal yapraklarını sınıflarına göre ayıran bir ağaç oluşturur. Sınıf etiketlemesi, aşağıda gösterilen çizim gibi işlem sonrası işlemleri hızlandırır. Kod, kimlikler için sayısal değerler kullanır. Bu ağaçta 52 derinliğe kadar çalışır (çiftler kullanarak; işaretsiz uzun tamsayılar kullanılıyorsa, maksimum derinlik 32'dir). Daha derin ağaçlar için (herhangi bir uygulamada olması pek olası değildir, çünkü en az k
* 2 ^ 52 puan söz konusu olacaktır), kimliklerin dizeler olması gerekir.
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)
}
Bu algoritmanın özyinelemeli bölme ve fethetme tasarımının (ve sonuç olarak işlem sonrası algoritmaların çoğunun) zaman gereksiniminin O (m) ve RAM kullanımının O (n) olduğu anlamına gelir m
. ve n
nokta sayısıdır. hücre başına minimum noktaya bölünmesiyle m
orantılıdır n
,k
. Bu, hesaplama sürelerini tahmin etmek için kullanışlıdır. Örneğin, n = 10 ^ 6 noktasını 50-99 noktalı hücrelere (k = 50) bölmek 13 saniye alırsa, m = 10 ^ 6/50 = 20000. Bunun yerine 5-9'a kadar bölmek istiyorsanız hücre başına nokta (k = 5), m 10 kat daha büyüktür, bu nedenle zamanlama yaklaşık 130 saniyeye kadar çıkar. (Hücreler küçüldükçe bir dizi koordinatı aracı bölme işlemi hızlandığından, gerçek zamanlama sadece 90 saniyeydi.) Hücre başına k = 1 noktaya kadar gitmek için yaklaşık altı kat daha uzun sürecek Yine de dokuz dakika, ve kodun bundan biraz daha hızlı olmasını bekleyebiliriz.
Daha ileri gitmeden önce, bazı ilginç düzensiz aralıklı veriler üretelim ve sınırlı dörtlü (0,29 saniye geçen süre) oluşturalım:
İşte bu grafikleri üretmek için kod. R
'S polimorfizminden yararlanır : points.quadtree
örneğin, points
işlev bir quadtree
nesneye her uygulandığında çağrılır . Bunun gücü, noktaları küme tanımlayıcılarına göre renklendirme fonksiyonunun aşırı basitliğinde belirgindir:
points.quadtree <- function(q, ...) {
points(q$lower, ...); points(q$upper, ...)
}
points.quadtree.leaf <- function(q, ...) {
points(q$value, col=hsv(q$id), ...)
}
Izgarayı çizmek biraz daha zordur, çünkü dörtlü bölümleme için kullanılan eşiklerin tekrarlı olarak kesilmesini gerektirir, ancak aynı özyinelemeli yaklaşım basit ve zariftir. İsterseniz kadranların çokgen temsillerini oluşturmak için bir varyant kullanı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!
Başka bir örnek olarak, 1.000.000 puan oluşturdum ve bunları her biri 5-9'luk gruplara ayırdım. Zamanlama 91.7 saniyeydi.
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=".")
Bir CBS ile nasıl etkileşime girileceğine bir örnek olarak , tüm dört hücreli hücreleri shapefiles
kitaplığı kullanarak bir çokgen şekil dosyası olarak yazalım . Kod, kırpma rutinlerini taklit eder lines.quadtree
, ancak bu kez hücrelerin vektör tanımlarını üretmesi gerekir. Bunlar shapefiles
kütüphane ile kullanım için veri çerçeveleri olarak çıkar .
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]))
}
Noktaların kendileri read.shp
(x, y) koordinatlarının bir veri dosyası kullanılarak veya içe aktarılarak doğrudan okunabilir .
Kullanım örneği:
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)
( xylim
Burada bir alt bölgeye pencere oluşturmak veya eşlemeyi daha büyük bir bölgeye genişletmek için istediğiniz herhangi bir kapsamı kullanın ; bu kod varsayılan olarak noktaların boyutuna göre değişir.)
Bu tek başına yeterlidir: bu çokgenlerin orijinal noktalara uzamsal birleşimi kümeleri tanımlayacaktır. Bir kez tanımlandığında, veritabanı "özetleme" işlemleri, her bir hücre içindeki noktaların özet istatistiklerini üretecektir.