How can I create a data frame containing raster data combined, seperated by shapefiles?

Please find one possible solution using sf, terra, exactextractr and dplyr libraries

Reprex

  • Step 1: read the files and compute the mean temperature for each multipolygon
library(sf)
library(terra)
library(exactextractr)


# Read the .shp file as a 'sf' object
shape_sf <- sf::st_read("GDL Shapefiles V4.shp")


# Read the raster as a 'Spatraster' object
Spatrast <- terra::rast("ras_light_1992.tif")


# Compute the mean value of the raster cells that intersect each multipolygon of the 'sf' object
# (this computation is weighted by the fraction of cells that are covered by the multipolygon).
mean_temp <- exactextractr::exact_extract(Spatrast, shape_sf, "mean", force_df = TRUE)


# To what the result (i.e. dataframe) looks like:
head(mean_temp)
#>          mean
#> 1 0.164738640
#> 2 0.000000000
#> 3 0.053336937
#> 4 0.123192482
#> 5 0.011922332
#> 6 0.007129772
  • Step 2: Add the resulting dataframe 'mean_temp' to the sf object 'shape_sf' as a new column called 'mean_temp'
names(mean_temp) <- "mean_temp"

shape_sf <- cbind(shape_sf, mean_temp)

# To what the 'sf' object looks like:
shape_sf
#> Simple feature collection with 1745 features and 7 fields
#> Geometry type: MULTIPOLYGON
#> Dimension:     XY
#> Bounding box:  xmin: -180 ymin: -55.98403 xmax: 180 ymax: 83.11042
#> Geodetic CRS:  WGS 84
#> First 10 features:
#>    GDLcode constant iso_code     country
#> 1  AFGr101    World      AFG Afghanistan
#> 2  AFGr102    World      AFG Afghanistan
#> 3  AFGr103    World      AFG Afghanistan
#> 4  AFGr104    World      AFG Afghanistan
#> 5  AFGr105    World      AFG Afghanistan
#> 6  AFGr106    World      AFG Afghanistan
#> 7  AFGr107    World      AFG Afghanistan
#> 8  AFGr108    World      AFG Afghanistan
#> 9  AGOr201    World      AGO      Angola
#> 10 AGOr202    World      AGO      Angola
#>                                                 region      shdi    mean_temp
#> 1  Central (Kabul Wardak Kapisa Logar Parwan Panjsher) 0.5739148 0.1647386402
#> 2                  Central Highlands (Bamyan Daikundi) 0.4840758 0.0000000000
#> 3             East (Nangarhar Kunar Laghman Nooristan) 0.4776733 0.0533369370
#> 4      North (Samangan Sar-e-Pul Balkh Jawzjan Faryab) 0.5148334 0.1231924817
#> 5        North East (Baghlan Takhar Badakhshan Kunduz) 0.4603950 0.0119223315
#> 6        South (Uruzgan Helmand Zabul Nimroz Kandahar) 0.4241354 0.0071297721
#> 7             South East (Ghazni Paktya Paktika Khost) 0.4891695 0.0005833496
#> 8                      West (Ghor Herat Badghis Farah) 0.4617800 0.0027360055
#> 9                                              Cabinda 0.6649382 1.9035018682
#> 10                                               Zaire 0.6010896 0.3108430207
#>                          geometry
#> 1  MULTIPOLYGON (((69.41367 33...
#> 2  MULTIPOLYGON (((65.32353 33...
#> 3  MULTIPOLYGON (((70.46561 33...
#> 4  MULTIPOLYGON (((66.38873 34...
#> 5  MULTIPOLYGON (((67.35538 34...
#> 6  MULTIPOLYGON (((60.89944 29...
#> 7  MULTIPOLYGON (((68.52644 31...
#> 8  MULTIPOLYGON (((61.12394 31...
#> 9  MULTIPOLYGON (((12.21127 -5...
#> 10 MULTIPOLYGON (((13.33589 -7...
  • Step 3: Getting the requested output

    From the sf object you can get what you are looking for using some functions of the dplyr library:

# If you need a dataframe with only the names of countries and mean temperatures
Requested_df <- shape_sf %>% 
  dplyr::select(.,country, mean_temp) %>% 
  sf::st_drop_geometry() %>% 
  dplyr::group_by(country) %>% 
  dplyr::summarise(mean_temp = round(mean(mean_temp),2)) %>% 
  as.data.frame()


head(Requested_df)
#>               country mean_temp
#> 1         Afghanistan      0.05
#> 2             Albania      0.34
#> 3             Algeria      2.01
#> 4             Andorra     15.62
#> 5              Angola      0.40
#> 6 Antigua and Barbuda      7.47

Created on 2022-01-13 by the reprex package (v2.0.1)


EDIT based on @dbaston comment

Here is the lighter version thanks to Dan Baston's comment.

library(sf)
library(terra)
library(exactextractr)


# Read the .shp file as a 'sf' object
shape_sf <- sf::st_read("GDL Shapefiles V4.shp")


# Read the raster as a 'Spatraster' object
Spatrast <- terra::rast("ras_light_1992.tif")


# Compute the mean value of the raster cells that intersect each multipolygon of the 'sf' object
# (this computation is weighted by the fraction of cells that are covered by the multipolygon).
# And include the 'country' column in the returned data frame.
mean_temp <- exactextractr::exact_extract(Spatrast, shape_sf, "mean", append_cols = "country")
                                                   

# Rename 'mean' column into 'mean_temp' column
colnames(mean_temp)[2] <- "mean_temp"


# To what the result (i.e. dataframe) looks like:
head(mean_temp)
#>       country   mean_temp
#> 1 Afghanistan 0.164738640
#> 2 Afghanistan 0.000000000
#> 3 Afghanistan 0.053336937
#> 4 Afghanistan 0.123192482
#> 5 Afghanistan 0.011922332
#> 6 Afghanistan 0.007129772


# If you need a dataframe with only the names of countries and mean temperatures
Requested_df <- mean_temp %>% 
  dplyr::group_by(country) %>% 
  dplyr::summarise(mean_temp = round(mean(mean_temp),2)) %>% 
  as.data.frame()


head(Requested_df)
#>               country mean_temp
#> 1         Afghanistan      0.05
#> 2             Albania      0.34
#> 3             Algeria      2.01
#> 4             Andorra     15.62
#> 5              Angola      0.40
#> 6 Antigua and Barbuda      7.47

Created on 2022-01-23 by the reprex package (v2.0.1)


Here is an example in which I show how to extract monthly climate data for each country. You should be able to replace the climate data with your own data.

library(geodata)
w <- world(path=".")
tmp <- worldclim_global("tavg", 10, ".")
e <- extract(tmp, w, mean)[,-1]
x <- cbind(w$NAME_0, round(e, 1))
colnames(x) <- c("country", month.abb)
head(x)
#      country  Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec
#1       Aruba 26.4 26.5 26.8 27.5 28.5 28.8 28.8 29.1 29.3 28.7 27.7 26.8
#2 Afghanistan -2.0  0.2  5.9 12.7 17.7 22.7 24.7 23.1 18.3 12.4  6.1  1.1
#3      Angola 22.7 22.8 22.8 22.4 20.7 18.5 18.2 19.9 22.3 23.3 22.9 22.7
#4       Åland -2.3 -3.6 -1.0  2.7  8.1 12.9 15.8 15.2 10.9  6.7  2.6 -0.5
#5     Albania  2.9  3.7  6.2  9.9 14.7 18.4 20.8 20.6 17.2 12.5  7.7  5.0
#6     Andorra -4.2 -3.6 -1.6  0.3  4.7  9.1 13.0 13.2  9.7  4.9  0.0 -2.6

To improve this you could use higher resolution climate data, and/or use more exact extraction with argument exact=TRUE or exactextractr.