Làm thế nào tôi có thể tạo lưới không đều chứa n điểm tối thiểu?


20

Cho một mẫu lớn (~ 1 triệu) điểm phân bố không đều - có thể tạo lưới không đều (về kích thước, nhưng cũng có thể có hình dạng không đều nếu có thể?) Sẽ chứa lượng n điểm tối thiểu được chỉ định ?

Nó ít quan trọng đối với tôi nếu các 'ô' được tạo ra của lưới như vậy chứa chính xác n số điểm hoặc ít nhất n điểm.

Tôi biết các giải pháp như genvecgrid trong ArcGIS hoặc Tạo lớp lưới trong QGIS / mmgis tuy nhiên tất cả chúng sẽ tạo ra các lưới thông thường sẽ dẫn đến một đầu ra với các ô trống (vấn đề nhỏ hơn - tôi chỉ có thể loại bỏ chúng) hoặc các ô có số điểm ít hơn n (vấn đề lớn hơn vì tôi cần một giải pháp để tổng hợp các ô đó, có thể sử dụng một số công cụ từ đây ?).

Tôi đã loay hoay vô ích và sẵn sàng cho cả các giải pháp thương mại (ArcGIS & tiện ích mở rộng) hoặc miễn phí (Python, PostGIS, R).


1
Làm thế nào "thường xuyên" lưới cần phải được? Tôi tự hỏi nếu bạn có thể thực hiện một số phân cấp phân cấp và sau đó chỉ cần cắt chương trình dendro để đáp ứng nhu cầu của bạn (mặc dù điều này có thể kéo dài những gì sẽ được định nghĩa là một cấu hình không gian thông thường). Tài liệu CrimeStat có một số ví dụ hay về kiểu phân cụm này .
Andy W

5
Bạn có thể vui lòng giải thích chính xác những gì bạn có nghĩa là một "lưới bất thường"? Nghe có vẻ như một oxymoron :-). Hơn nữa, mục đích của bài tập này là gì? Cũng lưu ý rằng các tiêu chí hoặc ràng buộc bổ sung có thể cần thiết: sau tất cả, nếu bạn đã vẽ một hình vuông xung quanh tất cả 1 triệu điểm, nó có thể được coi là một phần của lưới và nó sẽ chứa nhiều hơn n chúng. Bạn có thể sẽ không quan tâm đến giải pháp tầm thường này, mặc dù: nhưng tại sao không, chính xác?
whuber

@AndyW Cảm ơn. Ý tưởng tốt và đáng để khám phá. Sẽ có một cái nhìn. Kích thước & hình dạng của 'lưới' có tầm quan trọng thứ yếu đối với tôi - ưu tiên (do tính bảo mật dữ liệu) là 'ẩn' n tính năng đằng sau một
Radek

@whuber Cảm ơn là tốt. Tôi đồng ý - nhưng không chắc làm thế nào khác tôi có thể đặt tên cho phân vùng như vậy. Như đã đề cập ở trên - động lực chính của tôi là quyền riêng tư dữ liệu. Có các vị trí năm điểm (mà tôi không thể hiển thị trên bản đồ cuối cùng) Tôi muốn thể hiện chúng theo khu vực bao phủ chúng; và nhận trung bình / trung bình / vv. giá trị cho điều đó. Tôi đồng ý rằng có thể vẽ một hình chữ nhật hoặc thân lồi đại diện cho tất cả chúng - đó sẽ là sự bảo vệ quyền riêng tư dữ liệu cuối cùng mà tôi đoán? ;] Tuy nhiên - sẽ hữu ích hơn khi biểu diễn nó bằng các hình dạng giới hạn, giả sử 10 tính năng. Sau đó - tôi vẫn có thể bảo tồn mô hình không gian.
radek

1
IMO đưa ra mô tả của bạn Tôi sẽ sử dụng một số loại nội suy và hiển thị bản đồ raster (có lẽ băng thông thích ứng kích thước N tối thiểu của bạn sẽ đủ để làm mịn dữ liệu). Theo như CrimeStat, các tệp lớn nhất tôi đã sử dụng là khoảng 100.000 trường hợp tôi tin (và việc phân cụm chắc chắn sẽ mất thời gian). Có khả năng bạn có thể thực hiện một số khái quát hóa trước dữ liệu của mình để thể hiện nó dưới dạng ít trường hợp hơn và vẫn nhận được kết quả mong muốn cho bất cứ điều gì bạn muốn. Đây là một chương trình thực sự đơn giản, tôi khuyên bạn chỉ nên dành vài phút để dùng thử và tự mình xem.
Andy W

Câu trả lời:


26

Tôi thấy MerseyViking đã đề xuất một phần . 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 Rnhư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 knú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 kvà 2 * k-1 phần tử mỗi và (2) ánh xạ các góc phần tư.

RMã 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 đó msố các ô và nlà số điểm. mtỷ lệ với nchia 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):

Tứ giác

Đây là mã để sản xuất các lô này. Nó khai thác Rtính đa hình của nó: points.quadtreesẽ được gọi bất cứ khi nào pointshà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ập mô tả hình ảnh ở đây


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 shapefilesthư 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 shapefilesthư 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.shphoặ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 ô.


Ồ Tuyệt diệu. Sẽ cung cấp cho nó một shot với dữ liệu của tôi khi quay lại văn phòng =)
radek

4
Câu trả lời hàng đầu @whuber! +1
MerseyViking

1
(1) Bạn có thể đọc shapefiles trực tiếp với ( inter alia ) shapefilesgói hoặc nếu không bạn có thể xuất tọa độ (x, y) trong văn bản ASCII và đọc chúng với read.table. (2) Tôi khuyên bạn nên viết ra qtdưới hai hình thức: thứ nhất, dưới dạng shapefile điểm trong xyđó các idtrường được bao gồm dưới dạng định danh cụm; thứ hai, trong đó các phân đoạn dòng được vẽ bởi lines.quadtreeđược viết ra dưới dạng một shapefile polyline (hoặc trong đó xử lý tương tự ghi các ô dưới dạng một shapefile đa giác). Điều này đơn giản như sửa đổi lines.quadtree.leafthành đầu ra xylimnhư một hình chữ nhật. (Xem các chỉnh sửa.)
whuber

1
@whubber Cảm ơn rất nhiều cho một bản cập nhật. Mọi thứ hoạt động trơn tru. Rất xứng đáng +50, mặc dù bây giờ tôi nghĩ rằng nó xứng đáng +500!
radek

1
Tôi nghi ngờ các id tính toán không phải là duy nhất vì một số lý do. Thực hiện những thay đổi này trong định nghĩa quad: (1) khởi tạo id=1; (2) thay đổi id/2để id*2trong lower=dòng; (3) thực hiện một thay đổi tương tự như id*2+1trong upper=dòng. (Tôi sẽ chỉnh sửa câu trả lời của mình để phản ánh điều đó.) Điều đó cũng cần quan tâm đến việc tính toán diện tích: tùy thuộc vào hệ thống GIS của bạn, tất cả các khu vực sẽ dương hoặc tất cả sẽ âm. Nếu tất cả đều âm, đảo ngược danh sách cho xyvào cell.quadtree.leaf.
whuber

6

Xem liệu thuật toán này có đủ ẩn danh cho mẫu dữ liệu của bạn không:

  1. bắt đầu với một mạng lưới thông thường
  2. nếu đa giác có ít hơn ngưỡng, hợp nhất với hàng xóm xen kẽ (E, S, W, N) theo chiều kim đồng hồ.
  3. nếu đa giác có ít hơn ngưỡng, chuyển sang 2, khác đi đến đa giác tiếp theo

Ví dụ: nếu ngưỡng tối thiểu là 3:

thuật toán


1
Ma quỷ nằm trong các chi tiết: có vẻ như cách tiếp cận này (hoặc gần như bất kỳ thuật toán phân cụm liên kết nào) có nguy cơ để lại các điểm "mồ côi" nhỏ rải rác khắp nơi, sau đó không thể xử lý được. Tôi không nói rằng cách tiếp cận này là không thể, nhưng tôi sẽ duy trì sự hoài nghi lành mạnh trong trường hợp không có thuật toán thực tế và ví dụ về ứng dụng của nó cho một bộ dữ liệu điểm thực tế.
whuber

Quả thực cách tiếp cận này có thể có vấn đề. Một ứng dụng của phương pháp này mà tôi đã nghĩ về việc sử dụng các điểm làm đại diện cho các tòa nhà dân cư. Tôi nghĩ rằng phương pháp này sẽ hoạt động tốt ở các khu vực đông dân cư. Tuy nhiên, vẫn sẽ có trường hợp khi có một hoặc hai tòa nhà "ở giữa hư không" và sẽ mất rất nhiều lần lặp lại & sẽ dẫn đến các khu vực thực sự lớn để cuối cùng đạt đến ngưỡng tối thiểu.
radek

5

Tương tự như giải pháp thú vị của Paulo, làm thế nào về việc sử dụng thuật toán phân chia bốn cây?

Đặt độ sâu bạn muốn cho tứ giác đi đến. Bạn cũng có thể có số điểm tối thiểu hoặc tối đa trên mỗi ô để một số nút sẽ sâu hơn / nhỏ hơn các điểm khác.

Chia nhỏ thế giới của bạn, loại bỏ các nút trống. Rửa sạch và lặp lại cho đến khi các tiêu chí được đáp ứng.


Cảm ơn. Phần mềm nào bạn muốn giới thiệu cho điều đó?
radek

1
Về nguyên tắc đây là một ý tưởng tốt. Nhưng làm thế nào các nút trống phát sinh nếu bạn không bao giờ cho phép ít hơn số điểm tối thiểu dương trên mỗi ô? (Có rất nhiều loại quadtrees, vì vậy khả năng của các nút rỗng cho thấy bạn có trong tâm trí một mà chưa tương thích với các dữ liệu, điều này làm tăng lo ngại về tính hữu dụng của nó đối với nhiệm vụ thiết kế.)
whuber

1
Tôi hình dung nó như thế này: hãy tưởng tượng một nút có nhiều hơn ngưỡng tối đa của các điểm trong đó, nhưng chúng được nhóm về phía trên bên trái của nút. Nút sẽ được chia nhỏ, nhưng nút con dưới cùng bên phải sẽ trống, vì vậy nó có thể được cắt tỉa.
MerseyViking

1
Tôi thấy những gì bạn đang làm (+1). Bí quyết là chia nhỏ tại một điểm được xác định bởi tọa độ (chẳng hạn như trung vị của chúng), do đó đảm bảo không có ô trống. Mặt khác, tứ giác được xác định chủ yếu bởi không gian bị chiếm bởi các điểm và không phải là các điểm; cách tiếp cận của bạn sau đó trở thành một cách hiệu quả để thực hiện ý tưởng chung được đề xuất bởi @Paulo.
whuber

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.