add two-dimensional name on a list - r

I want to add two dimensions on the name of the list.
For example,
N <- 3
M <- 2
x <- list()
for(i in 1:N) {
for(j in 1:M){
Ps <- i
x[[paste0("element", i)]] <- Ps
}
}
>x
$element1
[1] 1
$element2
[1] 2
$element3
[1] 3
However, I want to return a result like:
$element1,method1
[1] 1
$element1,method2
[1] 1
$element2,method1
[1] 2
$element2,method2
[1] 2
$element3,method1
[1] 3
$element3,method2
[1] 3
I guess building a three-dimensional "array" may work well on this problem, but I need to use a list because multiple hierarchical time series forecast results only can be stored in a list but cannot be stored in an array. Anyone who can help me solve it? Thank you very much.

You can either use nested lists
x[[paste0("element", i)]][[paste0("method", j)]] <- list(Ps)
or simply make character strings describing what you have
x[[paste0("element", i, ",method", j)]] <- Ps

Related

Saving out from a model in a for loop in r

I have a dataframe like this one
ourmodel difference new_topic
1 2 0.08233167 1
2 3 0.07837389 2
3 1 0.15904427 3
4 3 0.05716799 4
5 1 0.13388058 3
6 3 0.09156650 3
and I wish to save each output from the model in the variable out. My approach doesn't seem to work - can anyone see what I'm doing wrong?
This is how I do:
library(rethinking)
out <- list()
for (i in unique(singo$new_topic)) {
i <- ulam(
alist(
difference ~ dnorm(mu, sigma),
mu <- a[ourmodel],
a[ourmodel] ~ dnorm(0.40, 0.15) ,
sigma ~ dexp(2)
), data = final, chains = 4, cores = 4)
out[[i]] <- precis(i, depth = 2)
}
I get the following error
Error in out[[i]] <- precis(i, depth = 2) : invalid subscript type 'S4'
You're making 2 mistakes:
1. You are iterating across S4 objects, rather than integers.
Rather than
for (i in unique(singo$new_topic))
You want
max_i <- length(unique(singo$new_topic))
for (i in 1:max_i)
The error you are getting is because you are iterating over the elements of singo and trying to subset with them, rather than with an integer.
This example might make the nature of the error clearer:
animals <- c("cow", "pig", "sheep")
## This works
for(i in 1:length(animals)){
print(animals[[i]])
}
#> [1] "cow"
#> [1] "pig"
#> [1] "sheep"
## This also works
for(i in animals){
print(i)
}
#> [1] "cow"
#> [1] "pig"
#> [1] "sheep"
## This does not
for(i in animals){
print(animals[[i]])
}
#> Error in animals[[i]]: subscript out of bounds
Created on 2022-11-18 with reprex v2.0.2
2. You are overwriting i
If you want to use i to subset your list, you should not overwrite the value of i in the first line of your list. So do something like:
for(i in 1:max_i){
## don't assign to i here:
j <- ulam(
## some code
)
## Use i as the index, j as the first argument to precis()
out[[i]] <- precis(j, depth = 2)
}
3. Bonus: It's better to make an empty list of the correct lenght.
So try:
out <- vector("list", length = max_i)
To initialise out before you run the for loop. This makes your code clearer and faster to run.

function to subset data supplying subset argument as text string

m <- matrix(1:4, ncol=2)
l <- list(a=1:3, b='c')
d <- data.frame(a=1:3, b=3:1)
I was wondering if it is possible to make a function that takes a base R object (matrix, vector, list or data.frame, ...) as well as a text that specifies the subset of the object.
f1 <- function(object, subset) {
# object'subset'
}
For instance
f1(m, '[1,1]') #to evaluate m[1,1]
f1(l, '[[1]][2:3]') #l[[1]][2:3]
f1(d, '$a') #d$a
would give us (respectively):
[1] 1
[1] 2 3
[1] 1 2 3
I guess the function need somehow to glue the two arguments before evaluating. I guess one could make a kind of interpreter for each bit of the subset text and the (for the matrix example) do something like:
`[`(1,1)
This would possible but I thought there would be an easier more direct way (my 'glue' above).
Well one way to go is to use eval(parse)) methodology, i.e.
f1 <- function(x, text){
eval(parse(text = paste0(x, text)))
}
f1('d', '$a')
#[1] 1 2 3
f1('m', '[1,1]')
#[1] 1
f1('l', '[[1]][2:3]')
#[1] 2 3
f1<-function(object, subset){
return(eval(parse(text=paste0(substitute(object),subset))))
}
> m=matrix(4,2,2)
> l=list(c(1,2,3),c(2,3,4))
> f1(m,'[1,1]')
[1] 4
> f1(l,'[[1]][1:2]')
[1] 1 2

Avoid storing null values when skipping an iteration in a for loop

Exist a way to avoiding to store null values in an iterative process when some condition is activated to skip to the next iteration? The intention of "how to solve" this problem is with the structure itself of the loop
[CONTEXT]:
I refer to the case when you need to use a storing mechanism inside a loop in conjunction with a conditional statement, and it is given the scenario where basically one of the possibles path is not of your interest. In the honor to give the treatment in the moment, and not posterior of the computation, you skip to the next iteration.
[EXAMPLE]
Suppose given a certain sequence of numbers, I interested only in stored the numbers of the sequence that are greater than 2 in a list.
storeGreaterThan2 <- function(x){
y <- list()
for (i in seq_along(x)) {
if (x[i] > 2) {
y[[i]] <- x[i]
} else {
next
}
}
y
}
The previous function deal with the final purpose, but when the condition to skip the iteration is activated the missing operation in the index is filled with a null value in the final list.
> storeGeaterThan2(1:5)
[[1]]
NULL
[[2]]
NULL
[[3]]
[1] 3
[[4]]
[1] 4
[[5]]
[1] 5
In the spirit of dealing with the problem inside the structure of the loop, how it could deal with that?
This is a rather strange example, and I wonder if it's an x-y problem. It may be better to say more about your situation and what you ultimately want to do. For example, there are different ways of trying to do this depending on if the function's input will always be an ascending sequence. #Dave2e's comment that there will be better ways depending of what you are really after is right on the mark, in my opinion. At any rate, you can simply removed the NULL elements before you return the list. Consider:
storeGreaterThan2 <- function(x){
y <- list()
for(i in seq_along(x)) {
if(x[i] > 2) {
y[[i]] <- x[i]
} else {
next
}
}
y <- y[-which(sapply(y, is.null))]
return(y)
}
storeGreaterThan2(1:5)
# [[1]]
# [1] 3
#
# [[2]]
# [1] 4
#
# [[3]]
# [1] 5
Here is a possible way to do this without ever having stored the NULL element, rather than cleaning it up at the end:
storeGreaterThan2 <- function(x){
y <- list()
l <- 1 # l is an index for the list
for(i in seq_along(x)){ # i is an index for the x vector
if(x[i] > 2) {
y[[l]] <- x[i]
l <- l+1
}
}
return(y)
}

Adding elements to a list in for loop in R

I'm trying to add elements to a list in a for loop. How can I set the field name?
L <- list()
for(i in 1:N)
{
# Create object Ps...
string <- paste("element", i, sep="")
L$get(string) <- Ps
}
I want every element of the list to have the field name dependent from i (for example, the second element should have "element2")
How to do this? I think that my error is the usage of get
It seems like you're looking for a construct like the following:
N <- 3
x <- list()
for(i in 1:N) {
Ps <- i ## where i is whatever your Ps is
x[[paste0("element", i)]] <- Ps
}
x
# $element1
# [1] 1
#
# $element2
# [1] 2
#
# $element3
# [1] 3
Although, if you know N beforehand, then it is better practice and more efficient to allocate x and then fill it rather than adding to the existing list.
N <- 3
x <- vector("list", N)
for(i in 1:N) {
Ps <- i ## where i is whatever your Ps is
x[[i]] <- Ps
}
setNames(x, paste0("element", 1:N))
# $element1
# [1] 1
#
# $element2
# [1] 2
#
# $element3
# [1] 3

indexing through values of a nested list using mapply

I have a list of lists, with each sub-list containing 3 values. My goal is to cycle through every value of this nested list in a systematic way (i.e. start with list 1, go through all 3 values, go to list 2, and so on), applying a function to each. But my function hits missing values and breaks and I've traced the problem to the indexing itself, which doesn't behave in the way I am expecting. The lists are constructed as:
pop <- 1:100
treat.temp <- NULL
treat <- NULL
## Generate 5 samples of pop
for (i in 1:5){
treat.temp <- sample(pop, 3)
treat[[i]] <- treat.temp
}
## Create a list with which to index mapply
iterations <- (1:5)
Illustrative function and results.
test.function <- function(j, k){
for (n in 1:3){
print(k[[n]][j])
}
}
results <- mapply(test.function, iterations, treat)
[1] 61
[1] 63
[1] 73
[1] NA
[1] NA
[1] NA
[1] NA
[1] NA
<snipped>
For the first cycle through 'j', this works. But after that it throws NAs. But if I do it manually, it returns the values I would expect.
> print(treat[[1]][1])
[1] 61
> print(treat[[1]][2])
[1] 63
> print(treat[[1]][3])
[1] 73
> print(treat[[2]][1])
[1] 59
> print(treat[[2]][2])
[1] 6
> print(treat[[2]][3])
[1] 75
<snipped>
I'm sure this is a basic question, but I can't seem to find the right search terms to find an answer here or on Google. Thanks in advance!
Edited to Add: MrFlick's answer works well for my problem. I have multiple list inputs (hence mapply) in my actual use. A more detailed example, with a few notes.
pop <- 1:100
years <- seq.int(2000, 2014, 1)
treat.temp <- NULL
treat <- NULL
year.temp <- NULL
year <- NULL
## Generate 5 samples of treated states, control states and treatment years
for (i in 1:5){
treat.temp <- sample(pop, 20)
treat[[i]] <- treat.temp
year.temp <- sample(years, 1)
year[[i]] <- year.temp
}
## Create a list with which to index mapply
iterations <- (1:5)
## Define function
test.function <- function(j, k, l){
for (n in 1:3){
## Cycles treat through each value of jXn
print(k[n])
## Holds treat (k) fixed for each 3 cycle set of n (using first value in each treat sub-list); cycles through sub-lists as j changes
print(k[1])
## Same as above, but with 2nd value in each sub-list of treat
print(k[2])
## Holds year (l) fixed for each 3 cycle set of n, cycling through values of year each time j changes
print(l[1])
## Functionally equivalent to
print(l)
}
}
results <- mapply(test.function, iterations, treat, year)
Well, you might be misunderstanding how mapply works. The function will loop through both of the iterations you pass as parameters, which means treat will also be subset each iteration. Essentially, the functions being called are
test.function(iterations[1], treat[[1]])
test.function(iterations[2], treat[[2]])
test.function(iterations[3], treat[[3]])
...
and you seem to treat the k variable as if it were the entire list. Also, you have your indexes backwards as well. But just to get your test working, you can do
test.function <- function(j, k){
for (n in 1:3) print(k[n])
}
results <- mapply(test.function, iterations, treat)
but this isn't really a super awesome way to iterate a list. What exactly are you trying to accomplish?

Resources