hmsc-r / HMSC

GNU General Public License v3.0
103 stars 37 forks source link

Error: variable 'v.focal' was fitted with type "nmatrix.1" but type "numeric" was supplied #65

Open stephanJG opened 4 years ago

stephanJG commented 4 years ago

WORKING+++++++++++++++++++++++++++++++++++++++ code of loop that predicts marginal effects for each of the 5 explanatory variables

MODEL
Hmsc object with 142 sampling units, 212 species, 6 covariates, 2 traits and 2 random levels
Posterior MCMC sampling with 4 chains each with 250 samples, thin 5 and transient 10000

v_env_names
[1] "VD10"         "agedomin"     "OldFor_1km"   "TotalPrecip"  "globRad_WHm2"

for (i in 1:length(v_env_names)){ 
  #gradients
  assign(paste0("grad_",v_env_names[i]),
         constructGradient(
           hM = MODEL,focalVariable =  v_env_names[i]
           ,#setting nonfocal to 1 (most likely value)
           non.focalVariables = c(list(xx=list(1)) %>%
                                    set_names(c(v_env_names,v_env_names)[i+1]),#"c" for i=max
                                  list(xx=list(1)) %>%
                                    set_names(c(v_env_names,v_env_names)[i+2]),
                                  list(xx=list(1)) %>%
                                    set_names(c(v_env_names,v_env_names)[i+3]),
                                  list(xx=list(1)) %>%
                                    set_names(c(v_env_names,v_env_names)[i+4]),
                                  list(xx=list(1)) %>%
                                    set_names(c(v_env_names,v_env_names)[i+5]))         )  )  }

NOT WORKING+++++++++++++++++++++++++++++++++++++++ simple code to predict net effect

Gradient=constructGradient(
  hM = MODEL,focalVariable =  "VD10")
Gradient=constructGradient(
  hM = MODEL,focalVariable =  v_env_names[i])
Error: variable 'v.focal' was fitted with type "nmatrix.1" but type "numeric" was supplied
traceback()
5: stop(gettextf("variable '%s' was fitted with type \"%s\" but type \"%s\" was supplied",
                 names(old)[wrong], old[wrong], new[wrong]), call. = FALSE,
        domain = NA)
4: .checkMFClasses(cl, m)
3: predict.lm(mylm, newdata = data.frame(v.focal = xx, stringsAsFactors = TRUE))
2: predict(mylm, newdata = data.frame(v.focal = xx, stringsAsFactors = TRUE))
1: constructGradient(hM = MODEL, focalVariable = "VD10")
stephanJG commented 4 years ago

I have problems solving the above error. It may be because I am using "assign" and "get". I hope you could help me with this. Many thanks in advance. Best jörg

jarioksa commented 3 years ago

The question related to the error message seems to be answered in https://stackoverflow.com/questions/22337495/

The error comes outside Hmsc from stats::predict.lm, and the ultimate reason is that the focal variable in the data frame was a matrix instead of a simple variable. This is related to the way you created your data frame.

Have you perhaps used tibbles instead of true blue data frames?

stephanJG commented 3 years ago

That is strange. Yes, I am working with tibbles, but my xdata is a data frame (%>% as.data.frame()is my last function). str(MODEL$XData) only indicates that the variables are scales and centered

$ VD10        : num [1:142, 1] -1.328 -0.664 -0.87 -1.818 -1.511 ...
  ..- attr(*, "scaled:center")= num 2.31

These is also -attr(*, "assign")= int [1:6] 0 1 2 3 4 5 in the str(MODEL$X). Is it due to either of these? Thanks for your help.

jarioksa commented 3 years ago

Indeed, VD10 is a matrix! It has two dimensions [1:142, 1], or 142 rows and 1 column. This is not so easy to spot, and str is one of the few functions that show this, but not super-clearly.

Here is an example of a tibble with one vector and one matrix:

> tib <- tibble(vec = runif(10), mat = matrix(runif(10))) # mat is a 10x1 matrix
> str(tib)
tibble [10 × 2] (S3: tbl_df/tbl/data.frame)
 $ vec: num [1:10] 0.764 0.374 0.108 0.893 0.568 ...
 $ mat: num [1:10, 1] 0.6239 0.5555 0.1722 0.0668 0.9795 ...

This will also survive transformation to a data frame:

> str(as.data.frame(tib))
'data.frame':   10 obs. of  2 variables:
 $ vec: num  0.764 0.374 0.108 0.893 0.568 ...
 $ mat: num [1:10, 1] 0.6239 0.5555 0.1722 0.0668 0.9795 ...

Both variables are OK if you make directly a data frame by-passing the tibble phase:

> str(data.frame(vec = runif(10), mat = matrix(runif(10))))
'data.frame':   10 obs. of  2 variables:
 $ vec: num  0.183 0.212 0.77 0.58 0.88 ...
 $ mat: num  0.39 0.158 0.826 0.453 0.489 ...

It seems that most Hmsc functions can handle one-column matrices similarly as dimensionless (in the R sense) vectors, but in constructGradient with type=2 (default) continuous variables are handled by R lm and functions, and its predict is picky. I have never seen this, but I would not touch tibbles with a six-foot pole (and in this thread you see one reason why).

This is a thing that is nearly impossible to spot and leads into very obscure error messages (like you see) which are extremely difficult to debug (as we have seen). I'll see how to handle this early in defining the Hmsc model, either by alerting the user or handling these within the Hmsc code.

stephanJG commented 3 years ago

Ok, wow, many thanks Jari! I will continue using tibbles as they offer very nice approaches for data handling, but I will take care of the imperfect transformation.

jarioksa commented 3 years ago

@stephanJG I'm just going through Hmsc github issues for the next CRAN release, and now I came to this issue. It seems that tibble does very little to close the gap between tibbles and data.frames:

tibble:::as.data.frame.tbl_df <-
    function (x, row.names = NULL, optional = FALSE, ...) 
{
    class(x) <- "data.frame"
    x
}

Although the tibblers suggest they have developed an improved kind of data frames, they just pretend they are equal, and all they do is to relabel tibbles as data.frames. Obviously we need to do something to close the gap within Hmsc.