मैं देख रहा हूँ MerseyViking एक की सिफारिश की है quadtree । मैं एक ही बात का सुझाव देने जा रहा था और इसे समझाने के लिए, यहाँ कोड और एक उदाहरण दिया गया है। कोड लिखा है, R
लेकिन पायथन को आसानी से कहने के लिए पोर्ट करना चाहिए।
विचार उल्लेखनीय रूप से सरल है: अंक को लगभग x- दिशा में आधे से विभाजित करें, फिर प्रत्येक दिशा में बारी-बारी से दिशाओं को y- दिशा के साथ दो हिस्सों को विभाजित करें, जब तक कि कोई और विभाजन अलग न हो जाए।
क्योंकि इरादा वास्तविक बिंदु स्थानों को छिपाने का है, यह विभाजन में कुछ यादृच्छिकता का परिचय देने के लिए उपयोगी है । ऐसा करने का एक सरल सरल तरीका यह है कि 50% से दूर एक छोटे से यादृच्छिक मात्रा में एक मात्रात्मक विभाजन पर विभाजित किया जाए। इस फैशन में (ए) बंटवारे के मूल्यों को डेटा निर्देशांक के साथ मेल खाने के लिए अत्यधिक संभावना नहीं है, ताकि अंक विभाजन द्वारा बनाए गए क्वाड्रंटों में विशिष्ट रूप से गिर जाएंगे, और (बी) बिंदु निर्देशांक क्वाडट्री से ठीक से पुनर्निर्माण करना असंभव होगा।
क्योंकि इरादा k
प्रत्येक क्वाड्री लीफ के भीतर न्यूनतम मात्रा में नोड्स बनाए रखने का है , हम क्वाडट्री के प्रतिबंधित रूप को लागू करते हैं। यह (1) समूहों के बीच k
और 2 * k
-1 तत्वों और (2) चतुष्कोणों का मानचित्रण करने वाले समूहों में (1) क्लस्टरिंग बिंदुओं का समर्थन करेगा ।
यह R
कोड नोड और टर्मिनल पत्तियों का एक पेड़ बनाता है, उन्हें कक्षा द्वारा अलग करता है। वर्ग लेबलिंग, पोस्ट-प्रोसेसिंग जैसे कि प्लॉटिंग में तेजी लाता है, नीचे दिखाया गया है। आईडी के लिए कोड संख्यात्मक मान का उपयोग करता है। यह पेड़ में 52 की गहराई तक काम करता है (युगल का उपयोग करते हुए; यदि अहस्ताक्षरित लंबे पूर्णांक का उपयोग किया जाता है, तो अधिकतम गहराई 32 है)। गहरे पेड़ों के लिए (जो किसी भी अनुप्रयोग में अत्यधिक संभावना नहीं है, क्योंकि कम से कम k
* 2 ^ 52 अंक शामिल होंगे), आईडी को तार होना होगा।
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)
}
ध्यान दें कि इस एल्गोरिथम का पुनरावर्ती विभाजन और जीतना डिजाइन (और, परिणामस्वरूप, अधिकांश पोस्ट-प्रोसेसिंग एल्गोरिदम) का मतलब है कि समय की आवश्यकता हे (एम) और रैम का उपयोग हे (एन) जहां m
संख्या है सेल और n
अंकों की संख्या है। प्रति सेल न्यूनतम बिंदुओं m
से n
विभाजित आनुपातिक है ,k
। यह गणना समय का आकलन करने के लिए उपयोगी है। उदाहरण के लिए, यदि विभाजन में 13 सेकंड लगते हैं n = 10 ^ 6 अंक 50-99 अंक (k = 50) की कोशिकाओं में, m = 10 ^ 6/50 = 20000। यदि आप इसके बजाय 5-9 तक विभाजन करना चाहते हैं प्रति सेल (k = 5) अंक, m 10 गुना बड़ा है, इसलिए समय लगभग 130 सेकंड तक चला जाता है। (क्योंकि उनके मिडल के चारों ओर निर्देशांक के एक सेट को विभाजित करने की प्रक्रिया तेज हो जाती है क्योंकि कोशिकाएं छोटी हो जाती हैं, वास्तविक समय केवल 90 सेकंड है।) प्रति सेल k = 1 बिंदु तक जाने के लिए लगभग छह गुना अधिक समय लगेगा। अभी भी, या नौ मिनट, और हम उम्मीद कर सकते हैं कि कोड वास्तव में इससे थोड़ा तेज हो।
आगे जाने से पहले, आइए कुछ दिलचस्प अनियमित डेटा उत्पन्न करें और उनका प्रतिबंधित क्वाडट्री बनाएं (0.29 सेकंड बीता हुआ समय):
यहाँ इन भूखंडों का उत्पादन करने के लिए कोड है। यह R
बहुरूपता का फायदा उठाता है: उदाहरण के लिए, points.quadtree
जब भी points
फ़ंक्शन किसी quadtree
ऑब्जेक्ट पर लागू होता है , तो उसे बुलाया जाएगा । इस की शक्ति उनके क्लस्टर आइडेंटिफ़ायर के अनुसार बिंदुओं को रंगने के लिए फ़ंक्शन की चरम सादगी में स्पष्ट है:
points.quadtree <- function(q, ...) {
points(q$lower, ...); points(q$upper, ...)
}
points.quadtree.leaf <- function(q, ...) {
points(q$value, col=hsv(q$id), ...)
}
ग्रिड को प्लॉट करना थोड़ा पेचीदा होता है क्योंकि इसमें बार-बार विभाजन के लिए इस्तेमाल होने वाले थ्रेसहोल्ड की क्लिपिंग की आवश्यकता होती है, लेकिन एक ही पुनरावर्ती दृष्टिकोण सरल और सुरुचिपूर्ण है। यदि वांछित हो तो चतुर्भुजों के बहुभुज निरूपण के निर्माण के लिए एक प्रकार का उपयोग करें।
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!
एक अन्य उदाहरण के रूप में, मैंने 1,000,000 अंक बनाए और उन्हें 5-9 के समूहों में विभाजित किया। टाइमिंग 91.7 सेकंड की थी।
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=".")
जीआईएस के साथ बातचीत करने के तरीके के एक उदाहरण के रूप में , आइए shapefiles
लाइब्रेरी का उपयोग करते हुए बहुभुज आकार के रूप में सभी चतुर्थांश कोशिकाओं को लिखें । कोड के कतरन दिनचर्या का अनुकरण करता है lines.quadtree
, लेकिन इस बार इसे कोशिकाओं के वेक्टर विवरण उत्पन्न करना है। ये shapefiles
लाइब्रेरी के साथ उपयोग के लिए डेटा फ़्रेम के रूप में आउटपुट हैं ।
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]))
}
read.shp
(X, y) निर्देशांक की डेटा फ़ाइल का उपयोग करके अंक स्वयं सीधे पढ़े जा सकते हैं ।
उपयोग का उदाहरण:
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
यहाँ किसी भी वांछित सीमा का उपयोग एक सबग्रोन में विंडो करने के लिए या एक बड़े क्षेत्र में मैपिंग का विस्तार करने के लिए; यह कोड बिंदुओं की सीमा तक परिभाषित करता है।)
यह अकेला पर्याप्त है: मूल बिंदुओं के लिए इन बहुभुजों का एक स्थानिक जुड़ाव समूहों की पहचान करेगा। एक बार पहचाने जाने के बाद, डेटाबेस "संक्षेप" संचालन प्रत्येक सेल के भीतर बिंदुओं के सारांश आंकड़े उत्पन्न करेगा।