De l' sp::over
aide:
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.
Donc, si vous convertissez votre SpatialPolygonsDataFrame
en SpatialPolygons
vous récupérez un vecteur d'index et vous pouvez sous-définir vos points sur 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
>
Pour les sceptiques, voici la preuve que la surcharge de conversion n'est pas un problème:
Deux fonctions - d'abord la méthode de Jeffrey Evans, puis ma version originale, puis ma conversion piratée, puis une version basée sur gIntersects
la réponse 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,]
}
Maintenant, pour un exemple réel, j'ai dispersé quelques points aléatoires sur l' columbus
ensemble de données:
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
Cela semble bon
plot(columbus)
points(pts)
Vérifiez que les fonctions font la même chose:
> identical(evans(pts,columbus),rowlings(pts,columbus))
[1] TRUE
Et exécutez 500 fois pour l'analyse comparative:
> 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
Selon mon intuition, ce n'est pas une surcharge importante, en fait, cela pourrait être moins d'une surcharge que la conversion de tous les index de ligne en caractère et retour, ou l'exécution de na.omit pour obtenir les valeurs manquantes. Ce qui conduit d'ailleurs à un autre mode de défaillance de la evans
fonction ...
Si une ligne du bloc de données de polygones est tout NA
(ce qui est parfaitement valide), la superposition avec SpatialPolygonsDataFrame
pour les points dans ce polygone produira un bloc de données de sortie avec tous les NA
s, qui evans()
tombera alors:
> 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
>
MAIS gIntersects
est plus rapide, même avec le balayage de la matrice pour vérifier les intersections dans R plutôt que dans le code C. Je soupçonne que ce sont les prepared geometry
compétences de GEOS, créant des index spatiaux - oui, avec prepared=FALSE
cela prend un peu plus de temps, environ 5,5 secondes.
Je suis surpris qu'il n'y ait pas de fonction pour renvoyer directement les indices ou les points. Quand j'ai écrit splancs
il y a 20 ans, les fonctions de point dans le polygone avaient les deux ...