De la sp::over
ayuda:
x = "SpatialPoints", y = "SpatialPolygons" returns a numeric
vector of length equal to the number of points; the number is
the index (number) of the polygon of ‘y’ in which a point
falls; NA denotes the point does not fall in a polygon; if a
point falls in multiple polygons, the last polygon is
recorded.
Entonces, si convierte su SpatialPolygonsDataFrame
a SpatialPolygons
, obtiene un vector de índices y puede subconjugar sus puntos en NA
:
> over(pts,as(ply,"SpatialPolygons"))
[1] NA 1 1 NA 1 1 NA NA 1 1 1 NA NA 1 1 1 1 1 NA NA NA 1 NA 1 NA
[26] 1 1 1 NA NA NA NA NA 1 1 NA NA NA 1 1 1 NA 1 1 1 NA NA NA 1 1
[51] 1 NA NA NA 1 NA 1 NA 1 NA NA 1 NA 1 1 NA 1 1 NA 1 NA 1 1 1 1
[76] 1 1 1 1 1 NA NA NA 1 NA 1 NA NA NA NA 1 1 NA 1 NA NA 1 1 1 NA
> nrow(pts)
[1] 100
> pts = pts[!is.na(over(pts,as(ply,"SpatialPolygons"))),]
> nrow(pts)
[1] 54
> head(pts@data)
var1 var2
2 0.04001092 v
3 0.58108350 v
5 0.85682609 q
6 0.13683264 y
9 0.13968804 m
10 0.97144627 o
>
Para los que dudan, aquí hay evidencia de que la sobrecarga de conversión no es un problema:
Dos funciones: primero el método de Jeffrey Evans, luego mi original, luego mi conversión pirateada, luego una versión basada en gIntersects
la respuesta de Josh O'Brien:
evans <- function(pts,ply){
prid <- over(pts,ply)
ptid <- na.omit(prid)
pt.poly <- pts[as.numeric(as.character(row.names(ptid))),]
return(pt.poly)
}
rowlings <- function(pts,ply){
return(pts[!is.na(over(pts,as(ply,"SpatialPolygons"))),])
}
rowlings2 <- function(pts,ply){
class(ply) <- "SpatialPolygons"
return(pts[!is.na(over(pts,ply)),])
}
obrien <- function(pts,ply){
pts[apply(gIntersects(columbus,pts,byid=TRUE),1,sum)==1,]
}
Ahora, para un ejemplo del mundo real, he dispersado algunos puntos aleatorios sobre el columbus
conjunto de datos:
require(spdep)
example(columbus)
pts=data.frame(
x=runif(100,5,12),
y=runif(100,10,15),
z=sample(letters,100,TRUE))
coordinates(pts)=~x+y
Se ve bien
plot(columbus)
points(pts)
Verifique que las funciones estén haciendo lo mismo:
> identical(evans(pts,columbus),rowlings(pts,columbus))
[1] TRUE
Y corra 500 veces para la evaluación comparativa:
> system.time({for(i in 1:500){evans(pts,columbus)}})
user system elapsed
7.661 0.600 8.474
> system.time({for(i in 1:500){rowlings(pts,columbus)}})
user system elapsed
6.528 0.284 6.933
> system.time({for(i in 1:500){rowlings2(pts,columbus)}})
user system elapsed
5.952 0.600 7.222
> system.time({for(i in 1:500){obrien(pts,columbus)}})
user system elapsed
4.752 0.004 4.781
Según mi intuición, no es una gran sobrecarga, de hecho, podría ser menos una sobrecarga que convertir todos los índices de fila en caracteres y viceversa, o ejecutar na.omit para obtener valores perdidos. Lo que incidentalmente conduce a otro modo de falla de la evans
función ...
Si una fila del marco de datos de polígonos es todo NA
(lo cual es perfectamente válido), entonces la superposición con SpatialPolygonsDataFrame
puntos en ese polígono producirá un marco de datos de salida con todos los NA
s, que evans()
luego caerán:
> columbus@data[1,]=rep(NA,20)
> columbus@data[5,]=rep(NA,20)
> columbus@data[17,]=rep(NA,20)
> columbus@data[15,]=rep(NA,20)
> set.seed(123)
> pts=data.frame(x=runif(100,5,12),y=runif(100,10,15),z=sample(letters,100,TRUE))
> coordinates(pts)=~x+y
> identical(evans(pts,columbus),rowlings(pts,columbus))
[1] FALSE
> dim(evans(pts,columbus))
[1] 27 1
> dim(rowlings(pts,columbus))
[1] 28 1
>
PERO gIntersects
es más rápido, incluso teniendo que barrer la matriz para verificar las intersecciones en R en lugar de en el código C. Sospecho que son las prepared geometry
habilidades de GEOS, la creación de índices espaciales, sí, con prepared=FALSE
esto lleva un poco más de tiempo, unos 5,5 segundos.
Me sorprende que no haya una función para devolver directamente los índices o los puntos. Cuando escribí hace splancs
20 años, las funciones de punto en el polígono tenían ambas ...