Search code examples
reviews

R "for loop" and/or Apply to transform several variables dynamically


I am trying to translate/replicate into R a shorthand "for loop" technique that I would use in EViews. I'm trying to replicate a "for loop" where I would divide one time series variable by another (vectors) and save it as a new series.

As I use a common naming convention (for example GDP (real), GDPn (nominal) and GDP_P (prices), see EViews example below), I can declare the list of variables once and use changes in the suffix ("n" or "_P") to create dynamic series names and loop through the calculations I need. My input data is national accounts expenditure series.

'EViews shorthand "for next" loop:

%CATS = "GDP CONS INV GOV EX IM"
 for %CATS {%cats}
   series {%cats}_P= {%cats}n / {%cats}
 next

'Which is shorthand replication of below ("series" declares a series of the subsequent name):

series GDP_P    = GDPn / GDP
series CONS_P   = CONSn / CONS
series INV_P    = INVn /  INV
series GOV_P    = GOVn / GOV
series EX_P     = EXn / EX
series IM_P     = IMn / IM

So far I've tried using an R for loop (which I have read is not the preferred way in R) by creating a vector of the series name and used "assign(paste" to do the calculation. An example is below but it does not work. From what I have read about the "for" command, the declared series for "i" can only be a vector of values or a vector of names with no further context:

cats<-c("GDP","CONS","GOV","INV","EX","IM")
for (i in cats){
  assign(paste(i, "_P",sep=""), paste(i, "n",sep="")/i)
}

I've also done a lot of reading into the "apply" function and derivatives, but I can't see how it works the above scenario. Any suggestions for how to do this in R is helpful.


Solution

  • Your function should work like this:

    cats<-c("GDP","CONS","GOV","INV","EX","IM")
    for (i in cats){
      assign(paste(i, "_P",sep=""), get(paste(i, "n",sep=""))/get(i))
    }
    

    The get will use the strings you provide and find the vector of that name.

    There's also a non-for-loop way of doing it, using the idea from one of the answers here:

    txt<-paste0(cats, "_P <- ", cats, "n/", cats)
    eval(parse(text=txt))
    

    txt will include a list of all the lines that you would have had to type to create all your vectors manually, and then eval(parse(text=txt)) takes each of those commands and executes them one by one.

    You can of course skip the assigning of the text to txt -- I just wanted it to be clearer what's going on here:

    eval(parse(text=paste0(cats, "_P <- ", cats, "n/", cats)))