1

I'm programming a box model with n layers. I want to generate a data frame for each layer I define in my box model and perform calculations in each column of each data frame. I've initialized the data frames using this code:

##Initialize layer energy+water balance dataframes
calcs <- c("Vwin", "Vwout", "Vsin","Vsout","Pistd","Vwnet","Psin","Psout","Vw","Vemax","Sw","Cp","Kt","Qwout","Qtop","Qbot","Qsides","Qnet","Tavg")
layer_tabs<-list()

for(i in 2:(layers-1)){
  nam <- paste("layer_",i,sep = "")
  assign(nam,data.frame(matrix(vector(),t,length(calcs),dimnames = list(c(),calcs))))
  append(layer_tabs, nam=nam)
}

Now for each column named in my calcs vector I need to perform a specific calculation in each layer data frame. I want to either append the layer data frames as they are generated to a list that I can loop through or use an apply function on and then write functions/equations for each column OR loop through the data frames by using the number in their variable name. My attempt to append the data frames as they were generated to the empty list "layer_tabs" returned the error:

Error in append(layer_tabs, nam = nam) : unused argument (nam = nam)
josliber
  • 43,891
  • 12
  • 98
  • 133
  • Try reading the help page, `?append` to determine if that function does what you need and how to use it if so. – Frank Mar 17 '16 at 14:03
  • The error message is because there is no argument named `nam` in `append`. Also, your `layer_tabs` object is not updating because you have to assign the result each time it is modified, `layer_tabs <- append(layer_tabs, nam`). – nrussell Mar 17 '16 at 14:04
  • 1
    You should neither be using `assign` nor `append`. I'm absolutely sure there is a much more readable and efficient solution (to your actual problem) just by seeing these two functions in your code. – Roland Mar 17 '16 at 14:25

2 Answers2

0

It sounds like you're trying to create a list with names "layer_2", "layer_3", ... containing empty data frames with column names from your calcs variable. You could do this in one line with replicate and setNames:

setNames(replicate(layers-2, data.frame(matrix(vector(), nrow=0, ncol=length(calcs),
                                               dimnames = list(c(),calcs))),
                   simplify=FALSE),
         paste0("layer_", 2:(layers-1)))
# $layer_2
#  [1] Vwin   Vwout  Vsin   Vsout  Pistd  Vwnet  Psin   Psout  Vw     Vemax  Sw    
# [12] Cp     Kt     Qwout  Qtop   Qbot   Qsides Qnet   Tavg  
# <0 rows> (or 0-length row.names)
# 
# $layer_3
#  [1] Vwin   Vwout  Vsin   Vsout  Pistd  Vwnet  Psin   Psout  Vw     Vemax  Sw    
# [12] Cp     Kt     Qwout  Qtop   Qbot   Qsides Qnet   Tavg  
# <0 rows> (or 0-length row.names)
# 
# $layer_4
#  [1] Vwin   Vwout  Vsin   Vsout  Pistd  Vwnet  Psin   Psout  Vw     Vemax  Sw    
# [12] Cp     Kt     Qwout  Qtop   Qbot   Qsides Qnet   Tavg  
# <0 rows> (or 0-length row.names)

Data:

calcs <- c("Vwin", "Vwout", "Vsin","Vsout","Pistd","Vwnet","Psin","Psout","Vw","Vemax","Sw","Cp","Kt","Qwout","Qtop","Qbot","Qsides","Qnet","Tavg")
layers <- 5
josliber
  • 43,891
  • 12
  • 98
  • 133
  • But of course there is no good reason to create empty data.frames. Next they'll fill them by appending rows in a loop. – Roland Mar 17 '16 at 15:23
  • @Roland yup, though without a wider view of the user's code I'm afraid there's not much we can do to help. – josliber Mar 17 '16 at 15:24
  • `rep(list(DF), 3)` is another option (alternative to `replicate(3,DF,simplify=FALSE)`) – Frank Mar 17 '16 at 15:27
0

I accomplished what I was attempting using the following code:

for(i in 2:(layers-1)){
 nam <- paste("layer_",i,sep = "")
 layer_tabs[[nam]]<-assign(nam,data.frame(t,matrix(data=rep(0,times=length(t)*length(calcs)),nrow=length(t),ncol=(length(calcs)),dimnames = list(c(),calcs))))

}

This allowed me to create data frames for an unknown number of layers and store them in a list where I can make calculations on all columns corresponding to a given variable in each data frame using a double for loop that will allow me to loop through each data frame and time:

for(i in 1:length(layer_tabs)){
  for(j in 1:length(t)){
    if(j==1){
      #assign initial values
      layer_tabs[[i]]$Sw[j] <- physical_inputs$sat[i+1]
    }
  }
}

This may not be the most efficient way of accomplishing my goal but it does the trick. Thank you for your comments. I tried the setNames approach but I couldn't figure out how to then store those data frames in a list without actually knowing how many layers there were. This post helped me the most:

Adding data frames as list elements (using for loop)

Community
  • 1
  • 1