rcaretpls

how to use R package `caret` to run `pls::plsr( )` with multiple responses


the caret::train() does not seem to accept y if y is a matrix of multiple columns.

Thanks for any help!


Solution

  • That's correct. Perhaps you want the tidymodels package? Kuhn has said there would be support for multivariate response in it. Here's evidence in favor of my suggestion: https://www.tidymodels.org/learn/models/pls/

    Do a search of that document for plsr:

    library(tidymodels)
    library(pls)
    
    get_var_explained <- function(recipe, ...) {
      
      # Extract the predictors and outcomes into their own matrices
      y_mat <- bake(recipe, new_data = NULL, composition = "matrix", all_outcomes())
      x_mat <- bake(recipe, new_data = NULL, composition = "matrix", all_predictors())
      
      # The pls package prefers the data in a data frame where the outcome
      # and predictors are in _matrices_. To make sure this is formatted
      # properly, use the `I()` function to inhibit `data.frame()` from making
      # all the individual columns. `pls_format` should have two columns.
      pls_format <- data.frame(
        endpoints = I(y_mat),
        measurements = I(x_mat)
      )
      # Fit the model
      mod <- plsr(endpoints ~ measurements, data = pls_format)
      
      # Get the proportion of the predictor variance that is explained
      # by the model for different number of components. 
      xve <- explvar(mod)/100 
    
      # To do the same for the outcome, it is more complex. This code 
      # was extracted from pls:::summary.mvr. 
      explained <- 
        drop(pls::R2(mod, estimate = "train", intercept = FALSE)$val) %>% 
        # transpose so that components are in rows
        t() %>% 
        as_tibble() %>%
        # Add the predictor proportions
        mutate(predictors = cumsum(xve) %>% as.vector(),
               components = seq_along(xve)) %>%
        # Put into a tidy format that is tall
        pivot_longer(
          cols = c(-components),
          names_to = "source",
          values_to = "proportion"
        )
    }
    #We compute this data frame for each resample and save the results in the different columns.
    
    folds <- 
      folds %>%
      mutate(var = map(recipes, get_var_explained),
             var = unname(var))
    #To extract and aggregate these data, simple row binding can be used to stack the data vertically. Most of the action happens in the first 15 components so let’s filter the data and compute the average proportion.
    
    variance_data <- 
      bind_rows(folds[["var"]]) %>%
      filter(components <= 15) %>%
      group_by(components, source) %>%
      summarize(proportion = mean(proportion))
    

    This might not be a reproducible code block. May need additional data or packages.