Propiedades y operadores de SpatialPointsDataFrame en R

14

He creado un objeto de tipo SpatialPointsDataFrameusando el sppaquete en R. Sin embargo, estoy confundido acerca de los @, $, . and []operadores y cuándo usarlos para acceder a las diferentes propiedades de mi objeto. Aquí está mi código de muestra:

library(sp)
library(rgdal)

#creating a SpatialPointsDataFrame with sample points in UTM
x <- c(15.2, 15.3, 15.4, 15.5, 15.7)
y <- c(50.4, 50.2, 50.3, 50.1, 50.4)
v1 <- c(1.0, 2.0, 3.0, 4.0, 5.0)
v2 <- c("a","b","b","c","a")
attributes <- as.data.frame(cbind(v1,v2))
xy <- cbind(x,y)
locationsDD <- SpatialPointsDataFrame(xy, attributes)
proj4string(locationsDD) <- CRS("+proj=longlat")
locations <- spTransform(locationsDD, CRS("+proj=utm +zone=33"))
plot(locations)

#using the different operators: WHEN TO USE @, $ or [] ?

#all these work!
property1 <- locations$v1
property2 <- locations@data$v1
property3 <- locations@data[,"v1"]
property4 <- locations@data["v1"]

#these also work
property5 <- locations@coords
property6 <- locations@bbox
property7 <- locations@coords[,2]

#these three work only in my special case
property8 <- locations@coords[,"y"]
property9 <- locations$x
property10 <- locations$y

#these don't work: $ operator is invalid for atomic vectors
property11 <- locations@coords$x
property12 <- locations@coords$y

¿Alguien podría ayudarme, cuándo usar los @, $, []operadores? Cuando intento leer la documentación ?SpatialPointsDataFrame, puedo ver las diferentes propiedades como coordso bboxpero estoy confundido sobre qué operador @, $, []usar para acceder a ellas o modificarlas.

jirikadlec2
fuente
1
Debido a que esta es realmente una pregunta sobre la Rsintaxis, no es particular del sppaquete o sus objetos. Rse instala con un tutorial: comience allí en su investigación. La Web y los medios impresos ofrecen una gran cantidad de recursos adicionales para el aprendizaje R.
whuber

Respuestas:

21

Los datos espaciales sp son objetos de clase S4 y están formados por ranuras (llamadas usando @) que contienen componentes de la clase de entidad espacial que se está representando (por ejemplo, @data contiene atributos, @coords contienen pares de coordenadas, etc.). Puede devolver los nombres de las ranuras de nivel superior utilizando slotNames (), pero no es recursivo y no devolverá nombres de ranuras anidadas para objetos de clase de polígono. Cada ranura puede contener una clase de objeto diferente y, antes de operar en ella, debe verificarse usando str () o class (). La ranura @data siempre es un objeto data.frame y @coords es una matriz, mientras que @polygons es un objeto de lista con ranuras adicionales (labpt, area, hole, ringDir y coords).

Los espacios disponibles y la organización de ellos dependen del tipo de clase de entidad que se represente. Los objetos SpatialPointsDataFrame son los más básicos, mientras que los objetos SpatialPolygonsDataFrame tienen anidamiento (como se ve arriba). Esta estructura anidada, que representa cada polígono, debe tenerse en cuenta utilizando algo como sapply para operar en cada objeto de lista (polígono).

Aquí hay un ejemplo que usa sapply para devolver el área de cada polígono iterando a través de los "polígonos" y luego las ranuras anidadas de "área".

sapply(slot(sdat, 'polygons'), function(i) slot(i, 'area')) 

En el caso de los objetos poligonales, dado que se almacenan como una lista para cada polígono, también puede usar la indexación de listas. Aquí hay un ejemplo para devolver el primer polígono (que da como resultado un objeto de clase "Polígono" y no SpatialPolygonsDataFrame):

sdat@polygons[[1]]

En versiones más recientes de sp, los desarrolladores han comenzado, en algunos casos, a eliminar la necesidad de llamar directamente a la ranura @data.

Por ejemplo, para indexar @data anteriormente:

sdat@data[sdat@data$att >= 0.5 ,]  

y ahora:

sdat[sdat$att >= 0.5 ,]

Sin embargo, como se indicó anteriormente, este no es el caso para las otras ranuras (por ejemplo, coordenadas, polígonos, etc.). En cuanto a cuándo usar [] o $, esto todavía depende del tipo de operación. Los corchetes "[]" se pueden usar para llamar a un nombre en un marco de datos, pero se usan principalmente para indexar, mientras que $ se usa específicamente para llamar a una columna en un marco de datos. La razón por la que una llamada "indirecta" a un nombre de columna funciona es que los desarrolladores han agregado funcionalidad para permitir una búsqueda recursiva a través del objeto sp. Sin embargo, para evitar conflictos de nombres (como en su ejemplo; tener columnas x, y en su marco de datos entraría en conflicto con los nombres x, y en los nombres de la matriz @coord) hay alguna comprobación de consistencia interna que explica por qué esto solo funciona en algunos instancias.

Una característica conveniente es que puede subconjugar un objeto espacial a través de un índice de fila. Aquí estoy subconjustando los primeros 10 objetos.

sub.sdat <- sdat[1:10,] 

O, alternativamente, una muestra aleatoria (n = 10) usando un vector de índice de fila.

rs.sdat <- sdat[sample(1:nrow(sdat), 10),]

Comprender la indexación y cómo usar corchetes es algo muy importante al escribir código R.

Editar (24/03/2017): Tenga en cuenta que la clase de entidad simple (sf), siguiendo el estándar GeoJSON, probablemente se convertirá en el nuevo estándar para objetos espaciales en R. Puede leer una descripción detallada de esta clase en el CRAN sf página web simple Características de R .

Jeffrey Evans
fuente
Gracias por una explicación detallada de lo que sucede detrás de escena. Parece que SpatialPointsDataFrameno solo se pueden recuperar las columnas @data, sino también las columnas @coords con el $operador sin la necesidad de llamar a la ranura @coords. Entonces sdat@coords$eastingda el mismo resultado que sdat$easting.
jirikadlec2
Parece que está llamando a una columna en <at> datos. Esto no es lo mismo que la ranura <at> coords. Notará que si llama a colnames (sdat <at> coords) devolverá los nombres de las columnas de la matriz: "coords.x1", "coords.x2". No es necesario mantener las coordenadas en el marco de datos y, dado que está duplicado, una cintura de memoria.
Jeffrey Evans
No. No estoy llamando a la columna en <at> datos. Usando SpatialPointsDataFrame de mi script de muestra, colnames(locations@coords)devuelve [1] "x" "y"pero colnames(locations@data)vuelve [1] "v1" "v2". ¿Quizás el comportamiento depende de qué función se utilizó para crear el SpatialPointsDataFrame?
jirikadlec2
En realidad tengo un error en mi primer comentario. sdat@coords$eastingno funciona porque sdat @ coords es una matriz. Pero sdat@coords[,"easting"]es equivalente a sdat@coords[,1]y a sdat$easting.
jirikadlec2
Una advertencia, colnames () se usa para devolver nombres de columna en una matriz, mientras que names () devolverá NULL. Aunque, los nombres () y colnames () funcionarán en un objeto de marco de datos como <at> data. La mejor manera de recuperar datos de la <at> matriz de coordenadas es indexarla: sdat <at> coords [, 1] o por nombre de columna sdat <at> coords [, "coords.x1"] pero como notó $ does No funciona porque es un objeto matriz.
Jeffrey Evans
4

Deberías intentar str(locations)aclarar esto.

por ejemplo, estos son correctos:

property2 <- locations@data$v1
property5 <- locations@coords
property6 <- locations@bbox
property7 <- locations@coords[,"x"]
property8 <- locations@coords[,2]

Y este property1 <- locations$v1funciona, porque hace referencia a la ubicación interna de data.frame, @data

Guillermo Olmedo
fuente
str(locations)me dio algunas buenas pistas. Ahora entiendo que @se utiliza para "ranura de una clase". Pero todavía no entiendo por qué property9 <- locations$xfunciona cuando names(locations)no contiene ninguna columna llamadax
jirikadlec2
1
Cuando crea el SpatialPointDataFrame, asigna x e y como nombres de coordenadas. Si observa ubicaciones @ coords, puede ver la matriz con las coordenadas. Además, si intenta crear una nueva columna en @data con el nombre "x", no puede, porque ya se usa como nombre de coordenadas.
Guillermo Olmedo
Todavía no entiendo qué tipo de 'magia' SpatialPointsDataFrameusa el objeto para acceder a las coordenadas con el $operador. Pero al menos me siento más cómodo al usarlo ahora. Ejecuté el siguiente código: colnames(locations@coords) <- c("easting","northing") Después de ejecutarlo, locations$eastingme da el vector de coordenadas xy me da el vector de coordenadas y locations$northing.
jirikadlec2
Creo que de alguna manera R considera las dos columnas para las coordenadas como dos columnas más de la parte del marco de datos de SpatialPointsDataFrame. Es por eso que puede tener una columna con el mismo nombre dentro de la ranura @data
Guillermo Olmedo
1
Parece que la denominación de las columnas en la @coordsmatriz de SpatialPointsDataFramedepende de cómo SpatialPointsDataFramese creó el objeto. Método uno: coordinates(sdat) <- x ~ ycambiará el nombre de las columnas a "coords.x1", "coords.x2". Método dos: sdat <- SpatialPointsDataFrame(xy, attributes)preservará los nombres de columna originales de la xymatriz.
jirikadlec2