I have a raster data set in R with numeric values ranging from 0 to 61.5, including some random NAs throughout. I would provide a reproducible data set, but I don't know how to create a raster with random NAs and I cannot share my actual data online. I simply need to iterate through each raster value and apply the following logic:

> for (i in 1:length(raster){  
>  if (value(i) >= 5.1) {value(i) = 1}  
>  else if (value(i) < 5.1) {value(i) = value(i)/5.1}  
>  else (is.na(value(i)) == TRUE) {value(i) = 0.000001} 
> }

I often do loop on data frames in R but I'm new to the raster format and can't quite get this up and running. I'm not sure how to access each raster value in a for loop and apply my conditional statements. If something isn't clear let me know in the comments and I will fix my question as needed.


If you can do this on a vector you can do this on a raster.

To do this on a vector, first set up a test vector so you can see if it works.

x = c(0, 1, 2, 3, NA, 5, 5.1, NA, 6, 7)

if I understand the first part, anything >= 5.1 becomes 1, anything less than is scaled by 5.1. That's this:

ifelse(x>=5.1, 1, x/5.1)

which looks like this:

[1] 0.0000000 0.1960784 0.3921569 0.5882353        NA 0.9803922 1.0000000
[8]        NA 1.0000000 1.0000000

and now we ifelse on the NAs to set them to 0.000001:

> ifelse(is.na(x),.000001, ifelse(x>=5.1, 1, x/5.1))
 [1] 0.0000000 0.1960784 0.3921569 0.5882353 0.0000010 0.9803922 1.0000000
 [8] 0.0000010 1.0000000 1.0000000

bit hard to tell how everything has mapped there so let's combine it with the original:

> cbind(x, ifelse(is.na(x),.000001, ifelse(x>=5.1, 1, x/5.1)))
 [1,] 0.0 0.0000000
 [2,] 1.0 0.1960784
 [3,] 2.0 0.3921569
 [4,] 3.0 0.5882353
 [5,]  NA 0.0000010
 [6,] 5.0 0.9803922
 [7,] 5.1 1.0000000
 [8,]  NA 0.0000010
 [9,] 6.0 1.0000000
[10,] 7.0 1.0000000

that all looks good.

To work this on a raster you can treat r[] as the vector of values in the raster. Let's make an example from x:

> r = raster(matrix(x, ncol=2))

so thats a 2x5 raster:

> as.matrix(r)
     [,1] [,2]
[1,]    0  5.0
[2,]    1  5.1
[3,]    2   NA
[4,]    3  6.0
[5,]   NA  7.0

then use r[] everywhere we had x and replace the values in r:

> r[] =  ifelse(is.na(r[]),.000001, ifelse(r[]>=5.1, 1, r[]/5.1))


> as.matrix(r)
          [,1]      [,2]
[1,] 0.0000000 0.9803922
[2,] 0.1960784 1.0000000
[3,] 0.3921569 0.0000010
[4,] 0.5882353 1.0000000
[5,] 0.0000010 1.0000000

Learning outcomes: R can work on entire vectors and is a zillion times faster when you do that instead of for loops; you can make a reproducible example even if you can't dish out the data; make small examples so you can verify by eye that your code works; rasters are vectors - if you can do something on a vector in R you can do it on a raster.

  • thank you very much for this clear and detailed answer! Using the square brackets to access raster values was very helpful and I also like the embedded ifelse statements, this is much easier than using a For loop. Finally, thanks for showing me how to setup an example data set. Your help is very much appreciated.
    – Andrew15
    Oct 31 '19 at 14:09
  • 1
    One argument that I would pose here is that, in practice, rasters can get quite large. One of the advantages to the raster package is that you can operate on rasters out of memory. By using bracket calls in rasters you are reading the raster into memory. If you have the RAM then I would say that this is the preferred method, at least by me, to operate on raster data. However, if the raster cannot fit into memory it may be an issue. Also, one must be mindful of managing objects as to not run out of memory, eg., for a large stacks not creating an object per raster but rather overwriting objects. Oct 31 '19 at 16:59
  • Good to know, thanks @Jeffrey Evans
    – Andrew15
    Nov 1 '19 at 14:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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