0

This is my first time posting here, so apologies in advance if there are any issues with my question or reproducible example. I've checked similar questions and their answers, but haven't been able to figure out where I'm going wrong here.

I have a raster brick of binary response variables that I am using in a set of logistic regressions. I have written a for loop to run each model and save the results to a list. When I test the code for one iteration (i.e., setting i=1), the model output is saved to the list as expected. However, when I run the loop, I end up with a null object.

Create simplified data for an example where r1 is the predictor variable and r2, r3 and r4 are response variables:

r1 <- r2 <- r3 <- r4 <- raster(nrow=10, ncol=10)
values(r1) <- sample(0:150000, 100, replace=T)

values(r2) <- sample(0:1, 100, replace=T)
values(r3) <- sample(0:1, 100, replace=T)
values(r4) <- sample(0:1, 100, replace=T)
Y_Vals <- brick(r2,r3,r4)

After running the following loop, the Models list is a null object (not even a list object anymore!):

Models <- list()
Models <- for(i in 1:nlayers(Y_Vals)){
  s <- stack(Y_Vals[[i]], r1)
  df <- data.frame(na.omit(values(s)))
  names(df) <- c("response_var", "pred_var")
  m <- glm(response_var~pred_var, data=df, family=binomial)
  Models[[i]] <- m
}

If I break it apart and only run it for one instance of i, the results are assigned to the list as I expect:

i <- 1

s <- stack(Y_Vals[[i]], r1)
df <- data.frame(na.omit(values(s)))
names(df) <- c("response_var", "pred_var")
m <- glm(response_var~pred_var, data=df, family=binomial)
Models[[i]] <- m

Models[[i]]

What is going wrong when the code is looped?

cm_kam
  • 3
  • 2
  • 1
    This `Models <- ` is not required where you started the for loop, also a better way to intialize an empty list is that , you can use this `Models <- vector('list', nlayers(Y_Vals))` – PKumar Mar 31 '21 at 16:14
  • Of course! So obvious once it's pointed out. Thanks! – cm_kam Mar 31 '21 at 17:02

2 Answers2

0

Your problem is (as said by Pkumar in the comments) that you are assigning your loop to your variable. If you for example try running the code segment

x <- list()
for(i in 1:10){
  x[[i]] <- rnorm(i)
}
x # List of length 10, containing vectors of length 1:10

x <- for(i in 1:10){
  x[[i]] <- rnorm(i)
}
x # NULL

The for-loop itself does not return a value, it simply iterates. So if you instead ran

Models <- list()
for(i in 1:nlayers(Y_Vals)){
  s <- stack(Y_Vals[[i]], r1)
  df <- data.frame(na.omit(values(s)))
  names(df) <- c("response_var", "pred_var")
  m <- glm(response_var~pred_var, data=df, family=binomial)
  Models[[i]] <- m
}

you would see the result you expect. Note that iteratively extending a list is inefficient however. So to be more efficient, you could instead start with Models <- vector('list', nlayers(Y_Vals)), this will increase your performance slightly for larger datasets.

Oliver
  • 8,169
  • 3
  • 15
  • 37
0

Your for loop assigns a model to a spot in the Models in every iteration. The for loop itself however, does not return a value. Therefore, by doing

Models <- for() {}

you assigned a null value into Models. Just remove the Models <- and you will be fine.

vermouth
  • 301
  • 2
  • 12