there seem to many answered questions about how to convert a list into a double, but nothing that seems to keep the structure of the list valid.
I have a nested list like that (R output):
my_list
[[1]]
[1] 1 3 4 8 11 13 17
[[2]]
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
[[3]]
[1] 2 14
Then I pass this list to JAGS in order to iterate over its elements. In the JAGS loop I want to iterate over the first, second and third element and then retrieve the numbers stored in there to be iterated over again in another loop. That means I want to access "1 3 4 8 11 13 17" of the first element and so on.
The code in the JAGS script that I use to iterate is like this:
for (j in 1:subjects) { # Subject-loop
for (i in my_list[j]) { # Trial loop
....
}
}
The background for this is that not all subjects have valid trials. so I need to pass JAGS the valid trials for each subject.
I intended to do that with a nested list like above. However, it turns out JAGS cannot deal with list - so now I try to convert it into something that JAGS can iterate over without losing the information which trials belong to which subject.
I need to keep the structure functioning so everything that just converts the list into a single vector does not help as I cannot iterate over that anymore.
Any suggestions? I have tried to just pass the list, but JAGS cannot deal with that and needs a "double". I also tried to convert it into a matrix, but failed to keep structure.
Thank you!
Update: I tried this, which works somewhat as matrixes seem to work with JAGS
list_as_matrix <- do.call(rbind, my_list)
But the nested lists have different lengths, so the empty columns in the matrix are just filled with the same values over an over again.
The JAGS error code is:
4 nodes produced errors; first error: 'list' object cannot be coerced to type "double"
CodePudding user response:
What about something like this:
l <- list(
c(1,3,4,8, 11,13,17),
c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20),
c(2, 14))
Turn your list into a matrix that is padded out with NA
values.
maxlen <- max(sapply(l, length))
mat <- t(sapply(l, function(x)c(x, rep(NA, maxlen-length(x)))))
# > mat
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16]
# [1,] 1 3 4 8 11 13 17 NA NA NA NA NA NA NA NA NA
# [2,] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# [3,] 2 14 NA NA NA NA NA NA NA NA NA NA NA NA NA NA
# [,17] [,18] [,19] [,20]
# [1,] NA NA NA NA
# [2,] 17 18 19 20
# [3,] NA NA NA NA
Then, for each subject, identify the first and last columns with valid data.
minvals <- 1
maxvals <- apply(mat, 1, function(x)max(which(!is.na(x))))
Then, in your JAGS model, you could pull the appropriate values out of mat
to identify the trial numbers.
for (j in 1:subjects) { # Subject-loop
for (i in minvals[j]:maxvals[j]) { # Trial loop
mat[j,i] ## gives you the trial number for each subject
}
}
CodePudding user response:
You can map lists which returns the initial list after an arbitrary function has been applied to each list member (recursively, too, if desired). In base R, you'd do this with lapply()
or Map()
. Package {purrr} extends this concept with a variety of convenient functions.
Example:
## base R
lapply(your_list, function(list_element) {some_JAGS_call(list_element)})
## purrr (plus pipe and formula notation)
your_list %>% map(~ some_JAGS_call(.x))
This online ressource on R and JAGS might be helpful.
Edit 1
If you, e.g., need to map my_list from a list of vectors to a list of matrices fit for JAGS, you lapply
(list-apply) the function as.matrix()
:
my_list_of_matrices <- lapply(my_list, function(el) as.matrix(el))
(Supply further arguments to as.matrix()
as required by your JAGS call.)
Edit 2
Gotcha: when you index a list with single brackets like in your loop:
for (i in my_list[j]) { # Trial loop
you will still obtain the list element as a list. Use double brackets:
for (i in my_list[[j]])
to pick the list element (e.g. a matrix, if so) without the sticky list part.