Home > OS >  Transform raster values
Transform raster values

Time:04-03

I used this to predict values on a raster stack but the values then need to be back-transformed as they are log values:

r_pred <- raster::predict(model=rf_model, object=raster_stack)

I tried (but it did not work):

values(r_pred) <- exp(r_pred)

Reclassify() looks promising but I am not sure where to start?

CodePudding user response:

The short answer is: you can likely just use:

r_back_transformed = exp(r_pred)

The long answer is that from the values docs:

In most cases it is better to use getValues rather than values. values is typically used in functions after a read* function has been used and it will return all the values that happen to be in memory at that point, or fail if there are no values in memory. In contrast getValues will read values from disk if necessary.

So you could use a combination of raster::getValues() and raster::setValues(). As in:

raster::setValues(r_pred) <- exp(raster::getValues(r_pred))

However, in most cases you can directly use the calc or stackApply functions. For example:

r_back_transformed = raster::calc(r_pred, exp)  

applies the exp functions to all layers of r_pred.

However, for a number of functions, raster algebra is natively implemented; from raster documentation chapter four: raster algebra):

Many generic functions that allow for simple and elegant raster algebra have been implemented for Raster* objects, including the normal algebraic operators such as , -, *, /, logical operators such as >, >=, <, ==, !} and functions such as abs, round, ceiling, floor, trunc, sqrt, log, log10, exp, cos, sin, max, min, range, prod, sum, any, all. In these functions you can mix raster objects with numbers, as long as the first argument is a raster object.

And you can use r_back_transformed = exp(r_pred).

Finally, terra::values() corresponds to raster::getValues()/raster::setValues() which may explain your initial intuition, and terra, the replacement of raster, natively supports some raster algebra. For non-natively supported functions, terra::app maps to raster::calc.

CodePudding user response:

The answers by hrvg are good, but I wanted to simplify that and add another approach, and illusrate with example data (from ?predict); and using terra (but this also applies to raster)

Example data

library(terra)
logo <- rast(system.file("ex/logo.tif", package="terra"))   
names(logo) <- c("red", "green", "blue")
p <- matrix(c(48, 48, 48, 53, 50, 46, 54, 70, 84, 85, 74, 84, 95, 85, 
   66, 42, 26, 4, 19, 17, 7, 14, 26, 29, 39, 45, 51, 56, 46, 38, 31, 
   22, 34, 60, 70, 73, 63, 46, 43, 28), ncol=2)

a <- matrix(c(22, 33, 64, 85, 92, 94, 59, 27, 30, 64, 60, 33, 31, 9,
   99, 67, 15, 5, 4, 30, 8, 37, 42, 27, 19, 69, 60, 73, 3, 5, 21,
   37, 52, 70, 74, 9, 13, 4, 17, 47), ncol=2)

xy <- rbind(cbind(1, p), cbind(0, a))
e <- extract(logo, xy[,2:3])
v <- data.frame(cbind(pa=xy[,1], e))

Model and model prediction

library(randomForest)
rfmod <- randomForest(pa ~., data=v)
r_pred <- predict(logo, rfmod)

You can now back-transform (I did not actually transform the input) the results like this

p <- exp(r_pred)

That could be expressed on one line like this

p <- predict(logo, rfmod) |> exp()

You can also do that like below, but that is not recommended as it is less efficient and not memory safe

v <- exp(values(r_pred))
p <- setValues(r_pred, v)

# or overwrite the values like this
# values(r_pred) <- exp(values(r_pred)) 

Or use app (calc with terra)

p <- app(r_pred, exp) 
# p <- calc(r_pred, exp)  # with raster

Alternatively you could write your own wrapper around the predict function and take care of the transformation there; but that would seem overkill in this instance.

f <- function(model, data, ...) {
    exp(predict(model, data, ...))
}
p <- predict(logo, rfmod, fun=f)
  • Related