'R terra:: subst not reclassifying correctly?

the terra::subst function appears to be returning incorrectly reclassified raster values, when using numeric vectors:

require(terra)
# dummy SpatRast
set.seed(234)
r1 <- rast(xmin=0, xmax=100, ymin=0, ymax=100, res=1, val=sample(1:10, 100^2, replace=T))
r1rc1 <- subst(r1, from = c(5,2,4,7,8,1,3,10,9,6) , to = c(1,3,3,3,2,2,1,2,3,0))

# (help: from = numeric value(s), to = numeric value(s). Normally a vector of the same length as 'from')
# output is wrong: 
terra::freq(r1)
      layer value count
 [1,]     1     1   974
 [2,]     1     2   978
 [3,]     1     3   979
 [4,]     1     4  1028
 [5,]     1     5  1021
 [6,]     1     6  1028
 [7,]     1     7  1003
 [8,]     1     8   986
 [9,]     1     9   991
[10,]     1    10  1012
>     terra::freq(r1rc1)
     layer value count
[1,]     1     0  1028
[2,]     1     1  3988
[3,]     1     2  3993
[4,]     1     3   991

# try different ways, output is wrong; 
r1rc2 <- subst(r1, from = 1:10 , to = c(2,3,1,3,1,0,3,2,3,2))
terra::freq(r1rc2)
     layer value count
[1,]     1     0  1028
[2,]     1     1  3952
[3,]     1     2  1998
[4,]     1     3  3022

r1rc3 <- subst(r1, from = 1:10 , to = c(1,3,3,3,2,2,1,2,3,0))
terra::freq(r1rc3)
     layer value count
[1,]     1     0  1012
[2,]     1     1  1977
[3,]     1     2  3035
[4,]     1     3  3976

do it with the old raster subs

require(raster)
# dummy raster
r1x <- raster(r1)
    
# substitute old values with desired values
r1rc1x <- subs(r1x, data.frame(from = c(5,2,4,7,8,1,3,10,9,6), to = c(1,3,3,3,2,2,1,2,3,0)))
    
freq(r1x)
      value count
 [1,]     1   974
 [2,]     2   978
 [3,]     3   979
 [4,]     4  1028
 [5,]     5  1021
 [6,]     6  1028
 [7,]     7  1003
 [8,]     8   986
 [9,]     9   991
[10,]    10  1012
>     freq(r1rc1x)
     value count
[1,]     0  1028
[2,]     1  2000
[3,]     2  2972
[4,]     3  4000

# all correct values. 


Solution 1:[1]

Don't know exactly why it doesn't work with terra::subst() but please find below one possible solution using terra::classify.

Reprex

  • Code
library(terra)

set.seed(234)
r1 <- rast(xmin=0, xmax=100, ymin=0, ymax=100, res=1, val=sample(1:10, 100^2, replace=T))

# Build a matrix "from-to"
rcl_r1rc1 <- as.matrix(data.frame(from = c(5,2,4,7,8,1,3,10,9,6) , to = c(1,3,3,3,2,2,1,2,3,0)))

# Classify values of 'r1'
r1rc1 <- terra::classify(r1, rcl_r1rc1)

# Output
terra::freq(r1rc1)
#>      layer value count
#> [1,]     1     0  1028
#> [2,]     1     1  2000
#> [3,]     1     2  2972
#> [4,]     1     3  4000

Created on 2022-03-02 by the reprex package (v2.0.1)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 lovalery