RStoolbox icon indicating copy to clipboard operation
RStoolbox copied to clipboard

Fails to run `superClass` when one of the raster layer is factor

Open bappa10085 opened this issue 1 year ago • 3 comments

I am trying to run superClass with a raster stack having both numeric and categorical layers. But it returns me the following error:

Error: variable 'Class' was fitted with type "numeric" but type "factor" was supplied

But if I use caret package directly for model building, the model runs fine. By default caret converts factor variable using one hot encoding. Here is a minimal, reproducible example

library(terra)
library(RStoolbox)

f <- system.file("ex/elev.tif", package="terra")
elevation <- rast(f)
slope <- terrain(elevation, "slope")
aspect <- terrain(elevation, "aspect")
plot(elevation)

#Make the aspect categorical 
m_aspect <- c(-Inf, -1, 1,  
              -1, 22.5, 2,
              22.5, 67.5, 3,
              67.5, 112.5, 4,  
              112.5, 157.5, 5,
              157.5, 202.5, 6,
              202.5, 247.5, 7,  
              247.5, 292.5, 8,
              292.5, 337.5, 9,
              337.5, Inf, 2)

rclmat_aspect <- matrix(m_aspect, ncol=3, byrow=TRUE)

rc_aspect <- classify(aspect, rclmat_aspect, include.lowest=TRUE)
plot(rc_aspect)

aspect_classes <- data.frame(Value = 1:9,
                             Class = c("Flat", "N","NE","E","SE","S","SW","W",
                                       "NW"))

levels(rc_aspect) <- aspect_classes

logo <- c(elevation, slope, rc_aspect)

p <- read.table(text = "Longitude Latitude
49.60 6.00
49.65 6.10
49.70 6.15
49.75 6.20
49.80 6.25
49.85 6.27
49.87 5.80
49.90 5.83
50.00 5.85
50.05 5.90", header = T)

a <- p + 0.01  

pb <- c(rep("Yes", nrow(p)), rep("No", nrow(a)))
pts <- cbind(pb, rbind(p, a))

sp.pts <- terra::vect(pts, geom=c("Latitude", "Longitude"), crs=crs(elevation))

v <- terra::extract(logo, sp.pts, xy = T, ID = F, bind=T)

## Fit classifier (splitting training into 70% training data, 30% validation data)
rf_mod <- superClass(logo, trainData = sf::st_as_sf(v), 
                     responseCol = "pb", 
                     model = "rf", tuneLength = 1, trainPartition = 0.7, 
                     predict = T,
                     predType = "prob", #for class probabilities
                     mode = "classification",
                     kfold = 3, na.rm=TRUE)

bappa10085 avatar Feb 16 '24 16:02 bappa10085

@bappa10085 You are correct, caret converts it, however, terra does not. I am first using terra::predict before feeding anything into caret which seems to have some problems with factors. I will investigate on that, thanks for reporting. For now, just convert your SpatRaster Class (the values of it) to numeric before it then gets coverted by caret again to factors. As follows:

logo$Class <- as.numeric(logo$Class)
rf_mod <- superClass(logo,
                     trainData = sf::st_as_sf(v),
                     responseCol = "pb",
                     model = "rf",
                     tuneLength = 1,
                     trainPartition = 0.7,
                     predict = T,
                     predType = "prob", #for class probabilities
                     mode = "classification",
                     kfold = 3, na.rm=TRUE)

plot(rf_mod$map)

KonstiDE avatar Feb 19 '24 02:02 KonstiDE