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)