मैं न्यूनतम n अंक युक्त अनियमित ग्रिड कैसे उत्पन्न कर सकता हूं?


20

असमान रूप से वितरित बिंदुओं के एक बड़े (~ 1 मिलियन) नमूने को देखते हुए - क्या अनियमित ग्रिड उत्पन्न करना संभव है (आकार में, लेकिन यदि संभव हो तो यह आकार में भी अनियमित हो सकता है?) जिसमें न्यूनतम अंक n निर्दिष्ट होंगे ?

यह मेरे लिए कम महत्व का है अगर इस तरह के ग्रिड के जेनरेट किए गए 'सेल' में बिल्कुल n अंक या कम से कम n अंक होते हैं।

मुझे आर्कजीआईएस में जीनवेकग्रिड जैसे समाधानों के बारे में पता है या क्यूजीआईएस / एमएमजीआईएस में ग्रिड लेयर बनाएं, लेकिन वे सभी नियमित ग्रिड बनाएंगे जिसके परिणामस्वरूप रिक्त कोशिकाओं (छोटी समस्या - मैं बस उन्हें त्याग सकता हूं) या बिंदुओं की गिनती के साथ कोशिकाएं n से कम (बड़ी समस्या है क्योंकि मुझे उन कोशिकाओं को एकत्र करने के लिए एक समाधान की आवश्यकता होगी, शायद यहाँ से कुछ उपकरण का उपयोग कर रहे हैं ?)।

मैं बिना किसी लाभ के चारों ओर घूम रहा हूं और वाणिज्यिक (आर्कजीआईएस और एक्सटेंशन) या मुफ्त (पायथन, पोस्टजीआईएस, आर) समाधानों के लिए खुला हूं।


1
ग्रिड को "नियमित" करने की आवश्यकता कैसे है? मुझे आश्चर्य है कि यदि आप कुछ पदानुक्रमिक क्लस्टरिंग कर सकते हैं और फिर अपनी आवश्यकताओं को पूरा करने के लिए डेंड्रोग्राम को काट सकते हैं (हालांकि यह संभवतः एक नियमित स्थानिक विन्यास के रूप में परिभाषित किया जाएगा)। क्राइमस्टैट प्रलेखन में इस प्रकार के क्लस्टरिंग के कुछ अच्छे उदाहरण हैं ।
एंडी डब्ल्यू

5
क्या आप वास्तव में समझा सकते हैं कि "अनियमित ग्रिड" से आपका क्या मतलब है? यह एक ऑक्सीमोरोन :-) जैसा लगता है। इस बिंदु पर अधिक, इस अभ्यास का उद्देश्य क्या होगा? ध्यान दें, भी, अतिरिक्त मानदंड या बाधाओं की आवश्यकता है: आखिरकार, यदि आपने सभी 1 मिलियन बिंदुओं के चारों ओर एक वर्ग खींचा है, तो इसे ग्रिड का हिस्सा माना जा सकता है और इसमें n की तुलना में अधिक होगा । आप शायद इस तुच्छ समाधान की परवाह नहीं करेंगे, लेकिन: क्यों नहीं, बिल्कुल?
whuber

@AndyW धन्यवाद। अच्छा विचार और लायक खोज। नजर होगी। प्राथमिकता (डेटा की गोपनीयता के कारण) 'छिपाएं' करने के लिए है - आकार और 'ग्रिड' के आकार मेरे लिए माध्यमिक महत्व का है n पीछे एक सुविधा है
राडेक

@whuber साथ ही धन्यवाद। मैं सहमत हूं - लेकिन मुझे यकीन नहीं था कि मैं इस तरह के विभाजन को कैसे नाम दे सकता हूं। जैसा कि ऊपर बताया गया है - मेरी मुख्य प्रेरणा डेटा गोपनीयता है। पांच बिंदु वाले स्थान (जो मैं अंतिम मानचित्र पर नहीं दिखा सकता) मैं उन्हें कवर करके क्षेत्र का प्रतिनिधित्व करना चाहता हूं; और माध्य / माध्य / आदि प्राप्त करें। उसके लिए मूल्य। मैं मानता हूं कि एक आयत या उत्तल पतवार को उन सभी का प्रतिनिधित्व करना संभव होगा - मुझे लगता है कि अंतिम डेटा गोपनीयता सुरक्षा होगी? ;] हालांकि - यह आकार बाउंडिंग द्वारा इसका प्रतिनिधित्व करने के लिए अधिक उपयोगी होगा, मान लीजिए कि 10 विशेषताएं हैं। तब - मैं अभी भी स्थानिक पैटर्न को संरक्षित कर सकता हूं।
radek

1
IMO ने आपका विवरण दिया कि मैं कुछ प्रकार के प्रक्षेप का उपयोग करूंगा और एक रेखापुंज मानचित्र (शायद एक अनुकूली बैंडविड्थ आपके न्यूनतम एन का आकार डेटा को सुचारू बनाने के लिए पर्याप्त होगा) प्रदर्शित करता है। जहां तक ​​क्राइमस्टैट, मेरे द्वारा उपयोग की जाने वाली सबसे बड़ी फाइलें लगभग 100,000 मामले हैं जो मुझे विश्वास है (और क्लस्टरिंग निश्चित रूप से समय के साथ ले जाएगा)। यह संभव है कि आप इसे कम मामलों के रूप में प्रतिनिधित्व करने के लिए अपने डेटा के कुछ पूर्व-सामान्यीकरण कर सकते हैं और अभी भी जो भी आप चाहते हैं उसके लिए वांछनीय परिणाम प्राप्त कर सकते हैं। यह वास्तव में एक सरल कार्यक्रम है, मैं यह सुझाव दूंगा कि इसे आज़माने और देखने के लिए बस कुछ ही मिनट लगेंगे।
एंडी डब्ल्यू

जवाबों:


26

मैं देख रहा हूँ 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 सेकंड बीता हुआ समय):

Quadtree

यहाँ इन भूखंडों का उत्पादन करने के लिए कोड है। यह 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यहाँ किसी भी वांछित सीमा का उपयोग एक सबग्रोन में विंडो करने के लिए या एक बड़े क्षेत्र में मैपिंग का विस्तार करने के लिए; यह कोड बिंदुओं की सीमा तक परिभाषित करता है।)

यह अकेला पर्याप्त है: मूल बिंदुओं के लिए इन बहुभुजों का एक स्थानिक जुड़ाव समूहों की पहचान करेगा। एक बार पहचाने जाने के बाद, डेटाबेस "संक्षेप" संचालन प्रत्येक सेल के भीतर बिंदुओं के सारांश आंकड़े उत्पन्न करेगा।


वाह! बहुत खुबस। कार्यालय में एक बार वापस मेरे डेटा के साथ एक शॉट देगा =)
radek

4
शीर्ष उत्तर @whuber! +1
MerseyViking

1
(1) आप पैकेज ( इंटर एलिया ) के साथ सीधे आकार-प्रकार पढ़ सकते हैं shapefilesया फिर आप ASCII पाठ में निर्देशांक (x, y) निर्यात कर सकते हैं और उनके साथ पढ़ सकते हैं read.table। (२) मैं qtदो रूपों में लिखने की सलाह देता हूं : पहला, एक बिंदु आकार के रूप में xyजहां idखेतों को क्लस्टर पहचानकर्ता के रूप में शामिल किया गया है; दूसरा, जहां रेखा के खंडों lines.quadtreeको पॉलीलाइन शेपफाइल के रूप में लिखा जाता है (या जहां अनुरूप प्रसंस्करण कोशिकाओं को पॉलीगॉन शेपफाइल के रूप में लिखता है)। यह आयत के रूप में lines.quadtree.leafआउटपुट xylimको संशोधित करने के रूप में सरल है । (संपादन देखें।)
whuber

1
@whubber एक अद्यतन के लिए बहुत बहुत धन्यवाद। सब कुछ सुचारू रूप से काम किया। अच्छी तरह से योग्य +50, हालांकि अब मुझे लगता है कि यह +500 लायक है!
राडेक

1
मुझे लगता है कि गणना किए गए आईडी किसी कारण से अद्वितीय नहीं थे। इन परिभाषाओं में बदलाव करें quad: (1) इनिशियलाइज़ करें id=1; (2) परिवर्तन id/2करने id*2में lower=लाइन; (३) पंक्ति id*2+1में समान परिवर्तन करें upper=। (मैं अपने उत्तर को प्रतिबिंबित करने के लिए संपादित करूंगा।) यह भी क्षेत्र गणना का ध्यान रखना चाहिए: आपके जीआईएस के आधार पर, सभी क्षेत्र सकारात्मक होंगे या सभी नकारात्मक होंगे। वे सभी नकारात्मक कर रहे हैं, के लिए सूचियों रिवर्स xऔर yमें cell.quadtree.leaf
whuber

6

देखें कि क्या यह एल्गोरिथ्म आपके डेटा नमूने के लिए पर्याप्त गुमनामी देता है:

  1. एक नियमित ग्रिड के साथ शुरू करें
  2. यदि बहुभुज दहलीज से कम है, तो पड़ोसी वैकल्पिक (ई, एस, डब्ल्यू, एन) सर्पिलिंग क्लॉकवाइज के साथ विलय करें।
  3. यदि बहुभुज की सीमा से कम है, तो 2 पर जाएं, अन्यथा अगले बहुभुज पर जाएं

उदाहरण के लिए, यदि न्यूनतम सीमा 3 है:

कलन विधि


1
शैतान विवरण में है: ऐसा लगता है कि यह दृष्टिकोण (या लगभग किसी भी एग्लोमेरेटिव क्लस्टरिंग एल्गोरिथ्म) को सभी जगह बिखरे हुए "अनाथ" अंक छोड़ने की धमकी देता है, जिसे तब संसाधित नहीं किया जा सकता है। मैं यह नहीं कह रहा हूं कि यह दृष्टिकोण असंभव है, लेकिन मैं एक वास्तविक एल्गोरिथ्म के अभाव में एक स्वस्थ संदेह को बनाए रखूंगा और एक यथार्थवादी बिंदु डेटासेट के लिए इसके आवेदन का उदाहरण।
whuber

वास्तव में यह दृष्टिकोण समस्याग्रस्त हो सकता है। इस पद्धति का एक अनुप्रयोग जिसे मैं आवासीय भवनों के प्रतिनिधित्व के रूप में उपयोग बिंदुओं के बारे में सोच रहा था। मुझे लगता है कि यह विधि अधिक घनी आबादी वाले क्षेत्रों में अच्छी तरह से काम करेगी। हालाँकि, अभी भी ऐसे मामले होंगे जब शाब्दिक रूप से एक या दो इमारतें 'बीच में' होंगी और इसमें बहुत अधिक पुनरावृत्तियाँ होंगी और इसके परिणामस्वरूप वास्तव में बड़े क्षेत्रों को न्यूनतम सीमा तक पहुँचना होगा।
radek

5

इसी तरह पाउलो के दिलचस्प समाधान के बारे में, एक चौकोर पेड़ उपखंड एल्गोरिथ्म का उपयोग कैसे करें?

उस गहराई को निर्धारित करें, जहाँ आप जाना चाहते हैं। आपके पास प्रति सेल में न्यूनतम या अधिकतम अंक भी हो सकते हैं, इसलिए कुछ नोड्स दूसरों की तुलना में गहरा / छोटा होगा।

अपनी दुनिया को उपविभाजित करें, खाली नोड्स को त्यागें। जब तक मापदंड पूरा न हो जाए तब तक रगड़ें और दोहराएं।


धन्यवाद। आप इसके लिए कौन सा सॉफ्टवेयर सुझाएंगे?
radek

1
सिद्धांत रूप में यह एक अच्छा विचार है। लेकिन अगर आप प्रति सेल सकारात्मक बिंदुओं से कम अंक की अनुमति नहीं देते हैं तो खाली नोड्स कैसे उत्पन्न होंगे? (वहाँ quadtrees के कई प्रकार है, तो खाली नोड्स की संभावना इंगित करता है आप मन एक है कि डेटा है, जो इरादा कार्य के लिए इसकी उपयोगिता के बारे में चिंताओं को जन्म देती है के लिए अनुकूल नहीं है में होती है।)
whuber

1
मैं इसे इस तरह से चित्रित करता हूं: कल्पना कीजिए कि एक नोड में बिंदुओं की अधिकतम सीमा से अधिक है, लेकिन वे नोड के शीर्ष-बाएं की ओर क्लस्टर होते हैं। नोड को उप-विभाजित किया जाएगा, लेकिन नीचे-दाएं बच्चे का नोड खाली होगा, इसलिए इसे छंटनी की जा सकती है।
MsyViking

1
मैं देख रहा हूं कि आप क्या कर रहे हैं (+1)। चाल निर्देशांक (जैसे उनके मध्यिका) द्वारा निर्धारित बिंदु पर उपविभाजित करना है, जिससे कोई खाली कोशिकाओं की गारंटी नहीं है। अन्यथा, चतुर्भुज मुख्य रूप से बिंदुओं के कब्जे वाले स्थान द्वारा निर्धारित किया जाता है और अंक खुद नहीं; आपका दृष्टिकोण तब @Paulo द्वारा प्रस्तावित सामान्य विचार को पूरा करने का एक प्रभावी तरीका बन जाता है।
व्हिबर

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.