Is there an sf-native (i.e. "correct") way of extracting everything except the geometry column from a simple features object? This works

df <- dplyr::select(as.data.frame(sf), -geometry)

but the select( , -geometry) step feels unnecessary. Also, it doesn't remove the geometry attributes.


4 Answers 4


To drop the geometry column, use st_drop_geometry():

nc <-  st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
nc_df2 <- nc %>% st_drop_geometry()
#> [1] "data.frame"

Before st_drop_geometry() was added to the sf package (in November, 2018), one could produce the same result using the st_set_geometry() function, like this:

nc <-  st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
#> [1] "sf"         "data.frame"

nc_df <- nc %>% st_set_geometry(NULL)
#> [1] "data.frame"

Set the st_geometry property to NULL.

nc <-  st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
## [1] "sf"         "data.frame"
st_geometry(nc) <- NULL
## [1] "data.frame"

Also (though this won't remove the attr(nc, "sf_column"):

nc <-  st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
  • I had tried nc$geometry <- NULL before, but your suggestion did the trick. Thank you. Jan 18, 2017 at 12:43
  • 1
    is there a piped version of this? sf %>% mutate(geometry = NULL) doesn't work
    – obrl_soil
    Apr 25, 2017 at 0:52
  • 3
    Maybe it's called "geom" and not "geometry"? (It's never going to be constant). Another way is ` x %>% st_set_geometry(NULL)`. Either of these might be in dev, not CRAN though I'm not checking carefully where I'm at locally.
    – mdsumner
    Apr 25, 2017 at 2:03
  • @mdsumner makes a great, indirect, point. Somebody has to actually write the method, it does not happen by magic. Since sf is a new object class in R many methods may not be available or not behave as expected. Dec 5, 2017 at 15:49
  • Is there a method that works for POINT or MULTIPOINT sf objects? When I try to do this with either of those I end up with a n × 0 df.
    – André.B
    May 5, 2020 at 20:30

why not simply select the columns that you would like?

as.data.frame(sf[,"some column name"])[,1]
  • This extracts a single column as a vector (sf$`some column name` is equivalent and simpler), and does not answer the question. Jul 17, 2020 at 22:54
  • well, you can index as much columns with this method as you like, so I do not really see why this should not solve the problem. In addition is it easier than the method suggested above.
    – joaoal
    Jul 22, 2020 at 19:52
  • 1. The problem was to extract the entire data.frame, not selected columns. This solution is not particularly well suited for this purpose, except for very small datasets, and certainly is not "sf-native". 2. I guess the simplicity of a method might be a matter of opinion, but st_set_geometry, st_drop_geometry and st_geometry are all mostly self-explanatory, and shorter than your method. Jul 22, 2020 at 20:15

as.data.frame(your_sf_object)[,-ncol(your_sf_object)] returns all the attribute columns except for its geometry. Also, use as.data.frame(your_sf_object)[,-8] if your 8th column is geometry.

If you prefer to use data.table rather than data.frame, you can use


or data.table(your_sf_object)[,-8,with=F] if your 8th column is geometry.

NOTE: This is my answer to an already old question, but time will come when I need this solution again but I forgot how I did it, so this is a good place to store the solution. Anyway, I got this solution from this thread. Sincerely, Yours Truly...

  • You know what, however the other answers might be better in their own special way, this subsetting method is what I needed to be able to export to … a widely used table calculation software, without creating another R object I need to think about rm()-ing.
    – thymaro
    May 5, 2023 at 13:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.