1

I want to loop through a list of country names contained world shape file and create individual shapefiles of each country. Then I want perform a calculation on the raster of each shapefile and coerce the results into a dataframe with the country name as an ID variable.

I have written this successfully for an individual country but am struggling to get it to loop correctly.

liech.map <- world.polys[world.polys$NAME == "Liechtenstein",]
plot(liech.map)

rasters <- stack(raster_1, raster_2)
rasters.values <- extract(rasters, liech.map)
df <- as.data.frame(rasters.values)
var <- as.data.frame(weighted.mean(x=df$raster_1, w=df$raster_2, na.rm=TRUE))

What I want to do is extract the list of country names from the world polygon shapefile, create a separate polygon for that country and loop it over every country. Then output 1 dataframe with the `var' in for each country with a country ID.

EDIT

Here is what I've managed to do so far, what I really want to be able to do is feed the following code a list of ID codes/names to loop over. I could of course copy and paste this manually 200-odd times, but this seems such a poor use of time!!

### leichenstein map
## 69.67 sec elapsed
tic()
LTU.map <- world.polys[world.polys$ISO3 == "LTU",]
rasters.values <- extract(rasters, LTU.map)
df <- as.data.frame(rasters.values)
rugged_LTU <- as.data.frame(weighted.mean(x=df$raster_1, w=df$raster_2, na.rm=TRUE))
var_LTU$iso3 <- "LTU"
rm(LTU.map)
toc()

# define master dataframe once
var_master <- var_LTU

### UK map
## 127.31 sec elapsed
tic()
GBR.map <- world.polys[world.polys$ISO3 == "GBR",]
rasters.values <- extract(rasters, GBR.map)
df <- as.data.frame(rasters.values)
rugged_GBR <- as.data.frame(weighted.mean(x=df$raster_1, w=df$raster_2, na.rm=TRUE))
var_GBR$iso3 <- "GBR"
var_master <- rbind(var_master, var_GBR)
rm(GBR.map)
toc()
Picko90
  • 11
  • 2
  • 2
    Hi Picko90, welcome to the site. Could you please edit your post with a more reproducible example? Something one can copy / paste and run would be ideal. This is usually easy if the package you use comes with some preloaded data. Right now, the structure of the objects you manipulate is not clear to me, which makes it hard to answer. – asachet Jun 10 '19 at 13:57
  • Hi, sorry I am a relative novice with R so I'm not too sure how to make a reproducible example...! – Picko90 Jun 10 '19 at 14:00
  • 2
    You can have a look [at this question](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example). In your example, I have no idea what `world.polys` is, or `raster_1` and `raster_2`, etc. Please try to post a self-contained example with enough code for people to run it. – asachet Jun 10 '19 at 14:04
  • @Picko90 , you can refer to [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). Also, related: [How to Ask](https://stackoverflow.com/help/how-to-ask). Your minimal, reproducible example will drastically increase the chances you receive assistance on this site. – SecretAgentMan Jun 10 '19 at 14:18

1 Answers1

1

So first thing first, we create a list to process. world.polys seems to be a data.frame or similar, we want to turn that into a named list.

polys_by_country <- split(world.polys, word.polys$ISO3)

Next we refactor the code for one country into a function:

extract_raster_value <- function(country_map) {
  # Here imagine country map is your LTU.mnap
  rasters.values <- extract(rasters, country_map)
  df <- as.data.frame(rasters.values)
  # compute weighted mean and implicitly return it (last value of function)
  weighted.mean(x=df$raster_1, w=df$raster_2, na.rm=TRUE)
}

OK so extract_raster_value takes a country map and returns a single number, a weighted mean. Note that there is no need to "clean up" the workspace using rm. All local variables defined in the function are only the function scope and do not pollute the global environment.

You can check it works. I have to assume it does, since you have not provided a reproducible example.

LTU.map <- world.polys[world.polys$ISO3 == "LTU",]
extract_raster_value(LTU.map)

The next step is to apply extract_raster_value to each element of polys_by_country.

You can use the apply or lapply functions from base R, but I prefer to use the map family of functions from the purrr package.

library("purrr")

# Apply process_country to each element of the list and return the list of results
map(polys_by_country, process_country)

This returns a named list where the names are the ISO3 names and the values are your weighted mean.

Instead of a list, you can get the result in a named numeric vector with:

result <- map_dbl(polys_by_country, process_country)

This completely avoids loops (or more precisely, hides the loop).

You can easily turn the result into a data.frame if you want:

result_df <- data.frame(
  country = names(result),
  value = result
)

Of course, there may be much better way to do it depending on what is actually in world.polys... Typically, if it is a data.frame, this will be much faster to run:

library("dplyr")
world.polys %>%
  group_by(ISO3) %>%
  summarise(wm = weighted.mean(raster1, raster2))
asachet
  • 6,620
  • 2
  • 30
  • 74
  • 2
    Thanks for this. I have updated my original post with how far I have managed to get! – Picko90 Jun 10 '19 at 15:31
  • 1
    OK - I edited my answer! Of course doing it manually is CRAZY :) Good reaction to want to loop. Once you realise how much you can automate, you never go back. Note that I was unable to actually test the code since you have not provided a minimal reproducible example (in particular, `world.polys` and `raster` are not defined). – asachet Jun 10 '19 at 15:54
  • Edited a typo: we need to use `polys_by_country` in the various map functions. – asachet Jun 10 '19 at 16:01
  • Thanks again, Antoine. This works up till the 'map' command. When I try to run it I get the error "Error in y[i, ] : cannot get a slot ("Polygons") from an object of type "NULL" ". I appreciate the need of a loop here because of my background in Stata, but for this I need to use R, which I am less familiar with! – Picko90 Jun 10 '19 at 16:37