Da sp::overajuda:
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.
Portanto, se você converter seu SpatialPolygonsDataFramepara SpatialPolygonsvocê, receberá de volta um vetor de índices e poderá definir seus pontos em 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 os que duvidam, aqui estão as evidências de que a sobrecarga da conversão não é um problema:
Duas funções - primeiro o método de Jeffrey Evans, depois meu original, depois minha conversão hackeada, depois uma versão baseada na gIntersectsresposta 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,]
}
Agora, para um exemplo do mundo real, eu espalhei alguns pontos aleatórios pelo columbusconjunto de dados:
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
Parece bom
plot(columbus)
points(pts)
Verifique se as funções estão fazendo a mesma coisa:
> identical(evans(pts,columbus),rowlings(pts,columbus))
[1] TRUE
E execute 500 vezes para fazer comparações:
> 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
De acordo com minha intuição, não é uma sobrecarga muito grande; na verdade, pode ser uma sobrecarga menor do que converter todos os índices de linha em caracteres e vice-versa ou executar na.omit para obter valores ausentes. Que, aliás, leva a outro modo de falha da evansfunção ...
Se uma linha do quadro de dados de polígonos for toda NA(o que é perfeitamente válido), a sobreposição SpatialPolygonsDataFramede pontos nesse polígono produzirá um quadro de dados de saída com todos os NAs, que evans()serão eliminados:
> 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
>
MAS gIntersectsé mais rápido, mesmo com a varredura da matriz para verificar as interseções no código R e não no código C. Suspeito que sejam as prepared geometryhabilidades do GEOS, criando índices espaciais - sim, com prepared=FALSEisso demora um pouco mais, cerca de 5,5 segundos.
Estou surpreso que não haja uma função para retornar diretamente os índices ou os pontos. Quando escrevi splancshá 20 anos, as funções point-in-polygon tinham ambas ...