Aus der sp::over
Hilfe:
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.
Wenn Sie also Ihre SpatialPolygonsDataFrame
in konvertieren , erhalten SpatialPolygons
Sie einen Vektor von Indizes zurück, und Sie können Ihre Punkte auf NA
folgende Werte setzen :
> 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
>
Für die Zweifler ist hier der Beweis, dass der Konvertierungsaufwand kein Problem ist:
Zwei Funktionen - zuerst Jeffrey Evans 'Methode, dann mein Original, dann meine gehackte Konvertierung, dann eine Version, gIntersects
die auf Josh O'Briens Antwort basiert:
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,]
}
Für ein reales Beispiel habe ich nun einige zufällige Punkte über den columbus
Datensatz verteilt:
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
Sieht gut aus
plot(columbus)
points(pts)
Überprüfen Sie, ob die Funktionen dasselbe tun:
> identical(evans(pts,columbus),rowlings(pts,columbus))
[1] TRUE
Und 500 Mal für das Benchmarking ausführen:
> 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
Meiner Intuition nach ist dies kein großer Aufwand, sondern möglicherweise ein geringerer Aufwand, als alle Zeilenindizes in Zeichen und zurück zu konvertieren oder na.omit auszuführen, um fehlende Werte abzurufen. Was übrigens zu einem anderen Fehlermodus der evans
Funktion führt ...
Wenn eine Zeile des Polygondatenrahmens alle ist NA
(was vollkommen gültig ist), dann erzeugt die Überlagerung mit SpatialPolygonsDataFrame
für Punkte in diesem Polygon einen Ausgabedatenrahmen mit allen NA
s, der evans()
dann abfällt:
> 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
>
ABER gIntersects
ist schneller, selbst wenn die Matrix gewobbelt werden muss, um Schnittpunkte in R statt in C-Code zu prüfen. Ich vermute, es liegt an den prepared geometry
Fähigkeiten von GEOS, räumliche Indizes zu erstellen - ja, prepared=FALSE
es dauert etwas länger, ungefähr 5,5 Sekunden.
Ich bin überrascht, dass es keine Funktion gibt, um die Indizes oder die Punkte direkt zurückzugeben. Als ich vor splancs
20 Jahren schrieb, hatten die Point-in-Polygon-Funktionen beide ...