24 votos

¿Cómo puedo generar irregular cuadrícula que contiene mínimo de n puntos?

Dada una grande (~ 1 millones) de la muestra de puntos distribuidos de manera desigual - es posible generar rejilla irregular (en tamaño, pero también podría ser de forma irregular, si es que eso es posible?) que contendrá mínimo especificado de n puntos?

Es de menor importancia para mí si genereted 'células' de dicha cuadrícula contiene exactamente n el número de puntos o al menos de n puntos.

Soy consciente de soluciones como genvecgrid en ArcGIS o Crear Capa de Cuadrícula en QGIS/mmgis sin embargo todos ellos crear mallas regulares que se traducirá en una salida con las celdas vacías (menor problema - yo podría simplemente descartarlos) o de células con recuento de puntos inferior a la de n (problema mayor desde que había necesidad de una solución para agregar esas células, probablemente con el uso de algunas herramientas de aquí?).

He estado googleando todo fue en vano y estoy abierto a ambos comercial (ArcGIS y extensiones) o libre (Python, PostGIS, R) de las soluciones.

30voto

cjstehno Puntos 131

Veo MerseyViking ha recomendado un quadtree. Yo iba a sugerir lo mismo y con el fin de explicar, aquí está el código y un ejemplo. El código está escrito en R pero debería puerto fácilmente, digamos, Python.

La idea es muy sencilla: dividir los puntos aproximadamente en la mitad en la dirección x, entonces recursivamente divide las dos mitades a lo largo de la dirección del eje y, alternando las direcciones en cada nivel, hasta que no hay más división que se desea.

Debido a que la intención es la de disimular la real ubicaciones de punto, es útil introducir un poco de aleatoriedad en las divisiones. Una rápida manera simple de hacer esto es para dividir a un cuantil establecer una pequeña cantidad aleatoria lejos del 50%. En esto de la moda (a) la división de valores es muy poco probable que coinciden con las coordenadas de los datos, de modo que los puntos se caen de forma exclusiva en cuadrantes creado por la partición, y (b) las coordenadas del punto será imposible reconstruir con precisión desde el quadtree.

Porque la intención es mantener una mínima cantidad k de nodos dentro de cada quadtree de la hoja, poner en práctica un restringido de quadtree. Se va a apoyar (1) de la agrupación de los puntos en grupos de entre k y 2*k-1 elementos de cada uno y (2) la asignación de los cuadrantes.

Este R código crea un árbol de nodos y terminales de las hojas, que la distingue por clase. La clase etiquetado acelera de post-procesamiento, tales como trazado, que se muestra a continuación. El código utiliza valores numéricos para los identificadores. Esto funciona hasta profundidades de 52 en el árbol (el uso de dobles; si unsigned long enteros se utilizan, la profundidad máxima es de 32). Para profundizar en los árboles (el cual es altamente improbable en cualquier aplicación, ya que, al menos, k * 2^52 puntos estarían involucrados), ids tendría que ser cadenas.

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)
}

Tenga en cuenta que el recurrente dividir y conquistar el diseño de este algoritmo (y, en consecuencia, de la mayoría de los post-procesamiento de los algoritmos) significa que el requisito de tiempo es O(m) y el uso de la RAM es O(n) donde m es el número de células y n es el número de puntos. m es proporcional a n dividido por el mínimo de puntos por celda, k. Esto es útil para la estimación de los tiempos de cómputo. Por ejemplo, si se tarda 13 segundos para la partición de n=10^6 puntos en las células de 50 a 99 puntos (k=50), m = 10^6/50 = 20000. Si desea lugar a la partición de abajo a 5-9 puntos por celda (k=5), m es 10 veces mayor, por lo que el calendario va hasta alrededor de 130 segundos. (Debido a que el proceso de dividir un conjunto de coordenadas alrededor de sus medios se hace más rápido a medida que las células se hacen más pequeños, el momento en que se fue de sólo 90 segundos). Ir todo el camino a k=1 punto por cada celda, se va a tomar alrededor de seis veces más todavía, o nueve minutos, y se puede esperar que el código, en realidad para ser un poco más rápido que eso.

Antes de continuar, vamos a generar unos interesantes irregularmente espaciados de datos y crear sus restringido quadtree (0.29 segundos de tiempo transcurrido):

Quadtree

Aquí está el código para producir estas parcelas. Explota R's polimorfismo: points.quadtree será llamado cada vez que el points función se aplica a un quadtree objeto, por ejemplo. El poder de esto es evidente en la extrema simplicidad de la función de color de los puntos de acuerdo a su identificador de clúster:

points.quadtree <- function(q, ...) {
  points(q$lower, ...); points(q$upper, ...)
}
points.quadtree.leaf <- function(q, ...) {
  points(q$value, col=hsv(q$id), ...)
}

El trazado de la red propia es un poco más complicada porque requiere repetidas recorte de los umbrales utilizados para el quadtree de partición, pero el mismo recursiva enfoque es simple y elegante. El uso de una variante para la construcción de planta poligonal, las representaciones de los cuadrantes, si se desea.

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!

Como otro ejemplo, yo generado 1.000.000 de puntos y dividido en grupos de 5 a 9 de cada uno. El tiempo fue de 91.7 segundos.

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=".")

enter image description here


Como un ejemplo de cómo interactuar con un SIG, vamos a escribir todos los quadtree células como un shapefile de polígonos utilizando la shapefiles biblioteca. El código emula las rutinas de recorte de lines.quadtree, pero esta vez se tiene para generar el vector de las descripciones de las células. Estos son de salida como de los marcos de datos para su uso con el shapefiles biblioteca.

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]))
}

Los puntos se pueden leer directamente el uso de read.shp o mediante la importación de un archivo de datos de (x,y) las coordenadas.

Ejemplo de uso:

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)

(El uso de cualquier medida deseada para xylim aquí a la ventana en una subregión o ampliar la asignación de una región más grande; este código de valores predeterminados para la medida de los puntos).

Esto por sí solo es suficiente: una unión espacial de los polígonos a los puntos originales identificará los grupos. Una vez identificado, la base de datos de "resumir" operaciones de generar las estadísticas de resumen de los puntos dentro de cada célula.

6voto

P.J. Tezza Puntos 131

A ver si este algoritmo da suficiente anonimato de sus datos de ejemplo:

  1. comience con una cuadrícula regular
  2. si el polígono tiene menos de umbral, en combinación con el vecino alterna (E, S, W, N) en espiral en sentido horario.
  3. si el polígono tiene menos de umbral, ir a 2, en otro caso, ir a la siguiente polígono

Por ejemplo, si el umbral mínimo es de 3:

algorithm

5voto

Symmetric Puntos 158

De manera similar a Paulo solución interesante, como sobre el uso de un quad árbol algoritmo de subdivisión?

Establecer la profundidad desea que el quadtree para ir. Usted también podría tener un número mínimo o máximo de puntos por cada celda, por lo que algunos nodos sería más profundo/más pequeño que los demás.

Subdividir su mundo, descartando nodos vacíos. Enjuague y repita hasta que se cumplen los criterios.

1voto

BenAlabaster Puntos 256

Otro enfoque es el de crear una rejilla fina, y usar el max-p algoritmo. http://pysal.readthedocs.org/en/v1.7/library/region/maxp.html

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X