De l' sp::overaide:
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 SpatialPolygonsDataFrameen SpatialPolygonsvous 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 gIntersectsla 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' columbusensemble 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 evansfonction ...
Si une ligne du bloc de données de polygones est tout NA(ce qui est parfaitement valide), la superposition avec SpatialPolygonsDataFramepour les points dans ce polygone produira un bloc de données de sortie avec tous les NAs, 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 gIntersectsest 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 geometrycompétences de GEOS, créant des index spatiaux - oui, avec prepared=FALSEcela 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 splancsil y a 20 ans, les fonctions de point dans le polygone avaient les deux ...