Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert a list of sf objects into one sf

I have a list of sf objects that I would like to row bind to create a single sf object. I'm looking for a function similar to data.table::rbindlist, that would stack the individual objects in an efficient manner.

Data for reproducible example:

my_list <- structure(list(structure(list(idhex = 4L, geometry = structure(list(
            structure(c(664106.970004623, 6524137.38910266), class = c("XY", 
            "POINT", "sfg"))), class = c("sfc_POINT", "sfc"), precision = 0, bbox = structure(c(xmin = 664106.970004623, 
            ymin = 6524137.38910266, xmax = 664106.970004623, ymax = 6524137.38910266
            ), class = "bbox"), crs = structure(list(epsg = 32633L, proj4string = "+proj=utm +zone=33 +datum=WGS84 +units=m +no_defs"), class = "crs"), n_empty = 0L)), row.names = 1L, class = c("sf", 
            "data.frame"), sf_column = "geometry", agr = structure(c(idhex = NA_integer_), .Label = c("constant", 
            "aggregate", "identity"), class = "factor")), structure(list(
            idhex = 9, geometry = structure(list(structure(c(665491.220375992, 
            6525002.7560692), class = c("XY", "POINT", "sfg"))), class = c("sfc_POINT", 
            "sfc"), precision = 0, bbox = structure(c(xmin = 665491.220375992, 
            ymin = 6525002.7560692, xmax = 665491.220375992, ymax = 6525002.7560692
            ), class = "bbox"), crs = structure(list(epsg = 32633L, proj4string = "+proj=utm +zone=33 +datum=WGS84 +units=m +no_defs"), class = "crs"), n_empty = 0L)), row.names = 1L, class = c("sf", 
            "data.frame"), sf_column = "geometry", agr = structure(c(idhex = NA_integer_), .Label = c("constant", 
            "aggregate", "identity"), class = "factor"))), .Dim = 1:2, .Dimnames = list(
            ".", NULL))

Note that data.table and sf libraries are not entirely compatible yet. So the rbindlist function returns an object that is not recognized as an `sf object.

single_sf <- rbindlist(my_list)
class(single_sf)
like image 397
rafa.pereira Avatar asked Jul 12 '18 19:07

rafa.pereira


3 Answers

df <- do.call(rbind, my_list)

> class(df)
[1] "sf"         "data.frame"

It is worth noting that dplyr::bind_rows and purrr::map_dfr does not work with sf objects, and thus rbind is better in this case.

like image 149
sebdalgarno Avatar answered Nov 05 '22 07:11

sebdalgarno


This is an old question but it is worth to note that the recent version of dplyr (> 0.9) can bind rows of sf objects (in a list or not):

single_sf <- dplyr::bind_rows(my_list)
class(single_sf)
[1] "sf"         "data.frame"

Other packages also provide options that can be used for binding sf objects (e.g. mapedit:::combine_list_of_sf(), sf:::rbind.sf and data.table::rbindlist), besides the do.call() option mentioned above (see https://github.com/r-spatial/sf/issues/798# for a discussion and some benchmarking). But the dplyr option also works for sf objects with data frames containing different number of columns, somenthing that do.call(), sf:::rbind.sf(), and data.table::rbindlist() cannot do, and was important for me working with a list of sf objects with different number of columns.

like image 45
R. Lima Avatar answered Nov 05 '22 08:11

R. Lima


I've found the fastest approach to do this is using data.table::rbindlist and then converting back to sf, as follows:

library(sf)
library(data.table)

# fast row bind
sf <- rbindlist(my_list)

# back to st
sf <- st_sf(sf)

like image 1
rafa.pereira Avatar answered Nov 05 '22 07:11

rafa.pereira