Da sp::over
ajuda:
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 SpatialPolygonsDataFrame
para SpatialPolygons
você, 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 gIntersects
resposta 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 columbus
conjunto 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 evans
função ...
Se uma linha do quadro de dados de polígonos for toda NA
(o que é perfeitamente válido), a sobreposição SpatialPolygonsDataFrame
de pontos nesse polígono produzirá um quadro de dados de saída com todos os NA
s, 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 geometry
habilidades do GEOS, criando índices espaciais - sim, com prepared=FALSE
isso 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 splancs
há 20 anos, as funções point-in-polygon tinham ambas ...