Estou trabalhando em um projeto de epidemiologia ambiental em que tenho exposições pontuais (~ 2.000 operações industriais de suínos - IHOs). Essas IHOs pulverizam em campos próximos, mas as gotas de água e o cheiro das fezes podem viajar quilômetros. Portanto, essas exposições pontuais recebem buffers de 3mi, e quero saber o número de exposições da IHO (de vários tipos - soma da quantidade de esterco, número de porcos, o que for; mais simples, apenas o número de buffers de exposição sobrepostos) por blocos censitários da NC (~ 200.000). Os blocos censitários de exclusão (azul) são (1) qualquer coisa nas 5 principais cidades mais populosas e (2) municípios que não fazem fronteira com um condado com uma IHO (nota: isso foi feito com a função gRelate e os códigos DE-9IM - muito liso!). Veja a imagem abaixo para um visual
O último passo é agregar a representação da exposição em buffer a cada bloco censitário. Aqui é onde eu estou perplexo.
Eu tive bons momentos com as funções% over% no pacote sp até agora, mas entendo pela vinheta over que poly-poly e poly-line over são implementados em rgeos. A vinheta cobre apenas poli-linha e poli-auto-referência, e não com agregação, por isso estou um pouco confuso sobre quais são minhas opções para poli-poli com agregação de funções, como soma ou média.
Para um caso de teste, considere o trecho abaixo, um tanto detalhado, que trabalha com o arquivo de fronteiras do país. Isso deve ser copiado e executado como está, pois estou usando uma semente aleatória para os pontos e estou baixando e descompactando o arquivo mundial no código.
Primeiro, criamos 100 pontos e depois usamos a função over com o argumento fn para adicionar o elemento no quadro de dados. Há muitos pontos aqui, mas dê uma olhada na Austrália: 3 pontos, número 3 como etiqueta. Por enquanto, tudo bem.
Agora transformamos geometrias para criar buffers, transformar de volta e mapear esses buffers. (Incluído no mapa anterior, já que estou limitado a dois links.) Queremos saber quantos buffers se sobrepõem a cada país - no caso da Austrália, a olho nu, é 4. Não posso, pela vida toda, descobrir o que está acontecendo embora para conseguir isso com a função over. Veja minha bagunça de uma tentativa nas linhas finais do código.
EDIT: Observe que um comentarista no r-sis-geo mencionou a função agregada - também referenciada na questão 63577 de troca de pilhas -, portanto, uma solução alternativa / fluxo pode ser através dessa função, mas não entendo por que precisaria ir agregar polypoly quando over parece ter essa funcionalidade para outros objetos espaciais.
require(maptools)
require(sp)
require(rgdal)
require(rgeos)
download.file("http://thematicmapping.org/downloads/TM_WORLD_BORDERS_SIMPL-0.3.zip", destfile="world.zip")
unzip("world.zip")
world.map = readOGR(dsn=".", "TM_WORLD_BORDERS_SIMPL-0.3", stringsAsFactors = F)
orig.world.map = world.map #hold the object, since I'm going to mess with it.
#Let's create 500 random lat/long points with a single value in the data frame: the number 1
set.seed(1)
n=100
lat.v = runif(n, -90, 90)
lon.v = runif(n, -180, 180)
coords.df = data.frame(lon.v, lat.v)
val.v = data.frame(rep(1,n))
names(val.v) = c("val")
names(coords.df) = c("lon", "lat")
points.spdf = SpatialPointsDataFrame(coords=coords.df, proj4string=CRS("+proj=longlat +datum=WGS84"), data=val.v)
points.spdf = spTransform(points.spdf, CRS(proj4string(world.map)))
plot(world.map, main="World map and points") #replot the map
plot(points.spdf, col="red", pch=20, cex=1, add=T) #...and add points.
#Let's use over with the point data
join.df = over(geometry(world.map), points.spdf, fn=sum)
plot(world.map, main="World with sum of points, 750mi buffers") #Note - happens to be the count of points, but only b/c val=1.
plot(points.spdf, col="red", pch=20, cex=1, add=T) #...and add points.
world.map@data = data.frame(c(world.map@data, join.df))
#world.map@data = data.frame(c(world.map@data, over(world.map, points.spdf, fun="sum")))
invisible(text(getSpPPolygonsLabptSlots(world.map), labels=as.character(world.map$val), cex=1))
#Note I don't love making labels like above, and am open to better ways... plus I think it's deprecated/ing
#Now buffer...
pointbuff.spdf = gBuffer(spTransform(points.spdf, CRS("+init=EPSG:3358")), width=c(750*1609.344), byid=T)
pointbuff.spdf = spTransform(pointbuff.spdf, world.map@proj4string)
plot(pointbuff.spdf, col=NA, border="pink", add=T)
#Now over with the buffer (poly %over% poly). How do I do this?
world.map = orig.world.map
join.df = data.frame(unname(over(geometry(world.map), pointbuff.spdf, fn=sum, returnList = F)) ) #Seems I need to unname this...?
names(join.df) = c("val")
world.map@data = data.frame(c(world.map@data, join.df)) #If I don't mess with the join.df, world.map's df is a mess..
plot(world.map, main="World map, points, buffers...and a mess of wrong counts") #replot the map
plot(points.spdf, col="red", pch=20, cex=1, add=T) #...and add points.
plot(pointbuff.spdf, col=NA, border="pink", add=T)
invisible(text(getSpPPolygonsLabptSlots(world.map), labels=as.character(world.map$val), cex=1))
#^ But if I do strip it of labels, it seems to be misassigning the results?
# Australia should now show 4 instead of 3. I'm obviously super confused, probably about the structure of over poly-poly returns. Help?
fonte
Respostas:
Obrigado pela pergunta clara e pelo exemplo reproduzível.
Seu entendimento está correto, e isso se resume a um bug no rgeos :: over, que foi corrigido há um mês, mas ainda não foi lançado no CRAN. A seguir, uma solução alternativa, se você estiver interessado apenas no número de interseções:
Estou usando
NROW
aqui em vez de,length
para que funcione com os rgeos errados (0,3-8, do CRAN) e com os corrigidos (0,3-10, do r-forge). A sugestão anterior de usartambém conta o número de interseções, mas apenas com a versão fixa do rgeos instalada. Sua vantagem, além de um nome mais intuitivo, é que ele retorna um
Spatial
objeto diretamente , com a geometria deworld.map
.Para que o rgeos 0.3-8 funcione, adicione
ao seu script, antes de usar
over
.fonte
SpatialPolygons,SpatialPolygonsDataFrame
deve retornar adata.frame
, mas retorna um vetor de índice idêntico a quandoy
teria sidoSpatialPolygons
.sp::aggregate
faz o que você faz com over de uma maneira mais amigável, retornando oSpatial
objeto em vez dodata.frame
. Os pacotes CRAN são mantidos por voluntários.Enquanto isso, criei um substituto rápido (e mal codificado) que cria o quadro de dados de que preciso, pois minha pergunta não é bem respondida pela solução somente de contagem acima ou "resolva os novos rgeos", que eu não sou suficientemente habilidoso para entender como fazer.
Esta função é claramente (1) incompleta (observe como eu ignoro o argumento fn) e (2) ineficiente, já que eu a encontro sem as poderosas manipulações de matriz do R / sapply ... (claramente eu estou vindo de outras linguagens sem esse poder), mas sinceramente, ainda estou confuso com o que a estrutura da função over retorna (lista de listas ...? E listas em branco se NA?). Pelo que vale a pena (edições bem-vindas), esta função faz o trabalho que eu preciso realizar com êxito e imita a ação das outras funções excedentes.
Edições bem-vindas:
fonte