[R] How can I avoid nested 'for' loops or quicken the process?

David Winsemius dwinsemius at comcast.net
Tue Dec 23 16:30:40 CET 2008


On Dec 23, 2008, at 9:55 AM, Brigid Mooney wrote:

> I have used some of your advice in making some changes to my  
> function and function call before reposting.
>
> Instead of nesting many 'for' loops, I have gotten to the point  
> where I only have one.    (Also, please note, I am pasting the  
> function calcProfit at the end of this message as it is a bit long.)
>
> This process works correctly, but still has a 'for' loop, which I  
> thought I would be able to avoid with 'apply'.
> ------------------------------------------------------------------------------------------------------------------
> # Sample iteration parameters (these can be vectors of arbitrary  
> length)
> # Need to iterate through all possible combinations of these  
> parameters
> Param <- list(long=c(.75, 1.5),
>                   short=c(-.5, -1),
>                   investment=10000,
>                   stoploss=c(-.015),
>                   comission=.0002,
>                   penny=3,
>                   volume=c(.02, .01),
>                   numU=2,
>                   accDefn=0:1 )
> CombParam <- expand.grid(Param)
>
> # Create sample X and Y data frames  for function call
> Y <- data.frame(SymbolID=10:14, OpeningPrice = c(1,3,10,20,60),  
> ClosingPrice = c(2,2.5,11,18,61.5), YesterdayClose= c(1,3,10,20,60),  
> MinTrVol = rep(10000000, times=5))
> X <- data.frame(SymbolID=10:14, weight = c(1, .5, -3, -.75, 2),  
> CPweight=c(1.5, .25, -1.75, 2, -1), noU = c(2,3,4,2,10))
>
> for (i in 1:length(CombParam$long))
>   {
>    if(i==1)
>      { Results <- calcProfit(CombParam[i,], X, Y)
>      } else {
>          Results <- rbind(Results, calcProfit(CombParam[i,], X, Y))
>        }
>   }
> ------------------------------------------------------------------------------------------------------------------
>
> However, when I try to replace this for loop with 'apply', I get the  
> following result:
>
> Results2 <- apply(CombParam, 1, calcProfit, X, Y)
> Error in IterParam$long : $ operator is invalid for atomic vectors

apply is giving calcProfit a named numeric vector and then calcProfit  
is trying to parse it with "$" which is an operator for lists. Try  
serial corrects of the form:

long <- IterParam["long"]

That seemed to let the interpreter move on to the next error ;-)

 > Results2 <- apply(CombParam, 1, calcProfit, X, Y)
Error in IterParam$short : $ operator is invalid for atomic vectors

-- 
David Winsemius

>
> Any advice that anyone could provide would be much appreciated.
>
> Here is the function which I am using:
>
> ------------------------------------------------------------------------------------------------------------------
> calcProfit <- function(IterParam,  marketData, dailyForecast) {
>     long <- IterParam$long
>     short <- IterParam$short
>     investment <- IterParam$investment
>     stoploss <- IterParam$stoploss
>     comission <- IterParam$comission
>     penny <- IterParam$penny
>     volume <- IterParam$volume
>     numU <- IterParam$numU
>     accDefn <- IterParam$accDefn
>
>     compareMarket <- merge(dailyForecast, marketData,  
> by.x="SymbolID", by.y="SymbolID")
>
>     weight <- ifelse(rep(accDefn, times=length(compareMarket 
> $weight))==1, compareMarket$weight, compareMarket$CPweight)
>
>     position <- ifelse((weight<=short & compareMarket$OpeningPrice >  
> penny & compareMarket$noU>=numU), "S",
>       ifelse((weight>=long & compareMarket$OpeningPrice > penny &  
> compareMarket$noU>=numU), "L", NA))
>     positionTF <- ifelse(position=="L" | position=="S", TRUE, FALSE)
>
>     estMaxInv <- volume*compareMarket$MinTrVol*compareMarket 
> $YesterdayClose
>
>     investbySymbol <- ifelse(positionTF==TRUE, ifelse(estMaxInv >=  
> investment, investment, 0))
>
>     opClProfit <- ifelse(position=="L", compareMarket$ClosingPrice/ 
> compareMarket$OpeningPrice-1,
>                     ifelse(position=="S", 1-compareMarket 
> $ClosingPrice/compareMarket$OpeningPrice, 0.0))
>
>     Gains <- investbySymbol*ifelse(opClProfit <= stoploss, stoploss,  
> opClProfit)
>     ProfitTable <- data.frame(SymbolID=compareMarket$SymbolID,  
> investbySymbol, Gains, percentGains=Gains/investbySymbol,
>                         LessComm=rep(comission,  
> times=length(Gains)), NetGains=Gains/investbySymbol-2*comission)
>
>     AggregatesTable <- data.frame( OutTotInvestment = sum(ProfitTable 
> $investbySymbol, na.rm=TRUE),
>         OutNumInvestments = sum(ProfitTable$investbySymbol,  
> na.rm=TRUE)/investment, OutDolProf = sum(ProfitTable$Gains,  
> na.rm=TRUE),
>         OutPerProf = sum(ProfitTable$Gains, na.rm=TRUE)/ 
> sum(ProfitTable$investbySymbol, na.rm=TRUE),
>         OutNetGains = sum(ProfitTable$Gains, na.rm=TRUE)/ 
> sum(ProfitTable$investbySymbol, na.rm=TRUE)-2*comission, OutLong =  
> long,
>         OutShort = short, OutInvestment = investment, OutStoploss =  
> stoploss, OutComission = comission, OutPenny = penny, OutVolume =  
> volume,
>         OutNumU = numU, OutAccDefn = accDefn )
>
>     return(AggregatesTable)
>   }
>
> ------------------------------------------------------------------------------------------------------------------
>
>
>
> On Mon, Dec 22, 2008 at 4:32 PM, David Winsemius <dwinsemius at comcast.net 
> > wrote:
> I do agree with Dr Berry that your question failed on several  
> grounds in adherence to the Posting Guide, so this is off list.
>
> Maybe this will give you  guidance that you can apply to your next  
> question to the list:
>
> > alist <- list("a","b","c")
> > blist <- list("ab","ac","ad")
>
> > expand.grid(alist, blist)
>  Var1 Var2
> 1    a   ab
> 2    b   ab
> 3    c   ab
> 4    a   ac
> 5    b   ac
> 6    c   ac
> 7    a   ad
> 8    b   ad
> 9    c   ad
>
> > apply( expand.grid(alist, blist), 1, function(x) paste(x[1], x[2],  
> sep=""))
> [1] "aab" "bab" "cab" "aac" "bac" "cac" "aad" "bad" "cad"
>
> > clist <- list("AA","BB")
>
> > apply(expand.grid(alist, blist, clist),1,function(x) paste(x[1],  
> x[2], x[3], sep=""))
>  [1] "aabAA" "babAA" "cabAA" "aacAA" "bacAA" "cacAA" "aadAA" "badAA"  
> "cadAA" "aabBB"
> [11] "babBB" "cabBB" "aacBB" "bacBB" "cacBB" "aadBB" "badBB" "cadBB"
>
> > dlist <- list(TRUE,FALSE)
>
> > apply(expand.grid(alist, blist, clist, dlist),1,function(x)  
> paste(x[1], x[2], x[3], (x[4]), sep=""))[8:12]
> [1] "badAATRUE" "cadAATRUE" "aabBBTRUE" "babBBTRUE" "cabBBTRUE"
>
>
> This could get unwieldily if the length of the lists are  
> appreciable, since the number of rows will be the product of all the  
> lengths. On the other hand you could create a dataframe indexed by  
> the variables in expand.grid's output:
>
> >  master.df <- data.frame( expand.grid(alist, blist, clist, dlist),
>                            results = apply(expand.grid(alist, blist,  
> clist,dlist),1,
>                                    function(x) paste(x[1], x[2],  
> x[3], (x[4]), sep="")))
>
>
>
> -- 
> David Winsemius
>
> On Dec 22, 2008, at 3:33 PM, Charles C. Berry wrote:
>
> On Mon, 22 Dec 2008, Brigid Mooney wrote:
>
> Hi All,
>
> I'm still pretty new to using R - and I was hoping I might be able  
> to get
> some advice as to how to use 'apply' or a similar function instead  
> of using
> nested for loops.
>
> Unfortunately, you have given nothing that is reproducible.
>
> The details of MyFunction and the exact structure of the list  
> objects are crucial.
>
> Check out the _Posting Guide_ for hints on how to formulate a  
> question that will elecit an answer that helps you.
>
> HTH,
>
> Chuck
>
>
>
> Right now I have a script which uses nested for loops similar to this:
>
> i <- 1
> for(a in Alpha) { for (b in Beta) { for (c in Gamma) { for (d in  
> Delta) {
> for (e in Epsilon)
> {
>     Output[i] <- MyFunction(X, Y, a, b, c, d, e)
>      i <- i+1
> }}}}}
>
>
> Where Output[i] is a data frame, X and Y are data frames, and Alpha,  
> Beta,
> Gamma, Delta, and Epsilon are all lists, some of which are numeric,  
> some
> logical (TRUE/FALSE).
>
> Any advice on how to implement some sort of solution that might be  
> quicker
> than these nested 'for' loops would be greatly appreciated.
>
> Thanks!
>
>        [[alternative HTML version deleted]]
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
>
>
> Charles C. Berry                            (858) 534-2098
>                                           Dept of Family/Preventive  
> Medicine
> E mailto:cberry at tajo.ucsd.edu               UC San Diego
> http://famprevmed.ucsd.edu/faculty/cberry/  La Jolla, San Diego  
> 92093-0901
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
>
>



More information about the R-help mailing list