ฉันเห็น MerseyViking ได้แนะนำควอดทรี ฉันจะแนะนำสิ่งเดียวกันและเพื่อที่จะอธิบายมันนี่คือรหัสและตัวอย่าง รหัสนี้เขียนขึ้นR
แต่ควรจะย้ายไปที่ Python อย่างง่ายดาย
แนวคิดนี้เรียบง่ายอย่างน่าทึ่ง: แบ่งคะแนนโดยประมาณครึ่งหนึ่งในทิศทาง x จากนั้นแบ่งสองส่วนซ้ำ ๆ กันตามทิศทาง y สลับทิศทางในแต่ละระดับจนกระทั่งไม่ต้องการแยกอีกต่อไป
เพราะเจตนาคือการปลอมตัวสถานที่จุดที่เกิดขึ้นจริงก็จะเป็นประโยชน์ที่จะแนะนำบางอย่างในการสุ่มแยก วิธีง่ายๆอย่างรวดเร็ววิธีหนึ่งในการทำเช่นนี้คือการแยกจำนวนชุดควอไทล์ออกเป็นจำนวนเล็กน้อยจาก 50% ในรูปแบบนี้ (a) ค่าการแยกนั้นไม่น่าเป็นไปได้สูงที่จะสอดคล้องกับพิกัดข้อมูลดังนั้นจุดจะลดลงเป็น quadrants ที่สร้างโดยการแบ่งพาร์ติชันและ (b) จุดพิกัดจะไม่สามารถสร้างได้อย่างแม่นยำจากควอดทรี
เนื่องจากความตั้งใจคือเพื่อรักษาจำนวนk
โหนดขั้นต่ำภายในแต่ละใบไม้ของควอดทรีเราจึงใช้รูปแบบควอดทรีที่ จำกัด มันจะสนับสนุน (1) คะแนนการจัดกลุ่มเป็นกลุ่มที่มีระหว่างk
และ 2 * k
-1 องค์ประกอบแต่ละและ (2) การทำแผนที่ Quadrants
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)
}
โปรดทราบว่าการออกแบบการหารและพิชิตซ้ำของอัลกอริทึมนี้ (และดังนั้นส่วนใหญ่ของอัลกอริธึมหลังการประมวลผล) หมายความว่าข้อกำหนดของเวลาคือการใช้ O (m) และ RAM คือ O (n) ซึ่ง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 วินาที (เนื่องจากกระบวนการแยกชุดของพิกัดรอบตัว middles ของพวกเขาได้เร็วขึ้นเมื่อเซลล์มีขนาดเล็กลงเวลาที่แท้จริงคือ 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=".")
เป็นตัวอย่างของวิธีการโต้ตอบกับ GISลองเขียนเซลล์ quadtree ทั้งหมดเป็นรูปหลายเหลี่ยมรูปร่างโดยใช้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
ที่นี่เพื่อหน้าต่างลงในภูมิภาคย่อยหรือเพื่อขยายการแมปไปยังภูมิภาคที่มีขนาดใหญ่กว่าโค้ดนี้มีค่าเริ่มต้นตามขอบเขตของคะแนน)
เพียงอย่างเดียวนี้ก็เพียงพอแล้ว:การรวมกันของรูปหลายเหลี่ยมเหล่านี้ไปยังจุดเริ่มต้นจะระบุกลุ่ม เมื่อระบุแล้วการดำเนินการ "สรุป" ฐานข้อมูลจะสร้างสถิติสรุปของคะแนนภายในแต่ละเซลล์