s-news
[Top] [All Lists]

Re: Simple conditional loop

To: <s-news@lists.biostat.wustl.edu>
Subject: Re: Simple conditional loop
From: "Huso, Manuela" <manuela.huso@oregonstate.edu>
Date: Wed, 30 May 2007 15:19:54 -0700
In-reply-to: <4D5DA98A54374044B7CC3F40A157B98BE77C6A@thuja>
References: <8C96912ADB6C413-9DC-7C31@mblk-r19.sysops.aol.com> <4D5DA98A54374044B7CC3F40A157B98BE77C6A@thuja>
Thread-index: Acea+61IqbSO1yaMRPuSCgAyW1HHdwHJcolQADmLR/A=
Thread-topic: [S] Simple conditional loop
Many thanks to Jim Pratt, Patrick Burns and Bill Dunlap for their prompt repsonses.  Of course, this was just a micro-example of my real case, so *why* I would do this might not be evident :-)  All the suggestions were helpful but I extend a special thanks to Bill Dunlap for not only showing me a much more elegant way to achieve my goal but in actually addressing why the crude code I had written worked in R but not S+.  His response is pasted below.
 
From Bill Dunlap:

ifelse() in Splus evaluates all of its arguments, including both alternatives.  In R, ifelse() only evaluates an alternative if it is possible that it might be used.  E.g., if all(test) is TRUE then the 'no' argument will not be evaluated.  In your case the test argument is a scalar so only one argument is evaluated in each iteration.
 
I think that using side effects, such as assignment, when giving arguments to a function is a bad idea because the details of argument evaluation may vary (in order or in whether they get evaluated at all).  E.g., if you trace() ifelse to see what its arguments are you will R's ifelse acts like Splus's in this case:
 
  > tracingState(TRUE)
  [1] FALSE
  > trace(ifelse, Quote(cat("ifelse: yes=", yes, "no=", no, "\n")))
  Tracing function "ifelse" in package "base"
  [1] "ifelse"
  > fallen<-c(1,rep(0,9))
  > for (i in 2:10)ifelse(i<5, fallen[i]<-1, fallen[i]<-0)
  trace: ifelse(i < 5, fallen[i] <- 1, fallen[i] <- 0)
  Tracing ifelse(i < 5, fallen[i] <- 1, fallen[i] <- 0) on entry
  ifelse: yes= 1 no= 0
  ...
  > fallen
   [1] 1 0 0 0 0 0 0 0 0 0
 
The following modification of your example pulls the assignments out of the argument list and works the same in both systems:
   fallen<-c(1,rep(0,9))
   for (i in 2:10)
      fallen[i] <- ifelse(fallen[i-1]==1, runif(1)<0.94, 0)
 
By the way, using if instead of ifelse in this case is probably faster.
   fallen <- c(1,rep(0,9))
   for (i in 2:10)
      fallen[i] <- if (fallen[i-1]==1) runif(1)<0.94 else 0
 
Doing tricks with cumsum or cumprod would be faster still.
E.g.,
   fallen <- c(1, runif(9) < 0.94)
   fallen <- cumprod(fallen)
 
----------------------------------------------------------------------------
Bill Dunlap
Insightful Corporation
bill at insightful dot com
360-428-8146

>::<>::<>::<>::<>::<>::<>::<>::<>::<>::<
Manuela Huso
Consulting Statistician
Department of Forest Science
201H Richardson Hall
Oregon State University
Corvallis, OR   97331
ph: 541.737.6232
fx: 541.737.1393

 


From: s-news-owner@lists.biostat.wustl.edu [mailto:s-news-owner@lists.biostat.wustl.edu] On Behalf Of Huso, Manuela
Sent: Tuesday, May 29, 2007 11:52 AM
To: s-news@lists.biostat.wustl.edu
Subject: [S] Simple conditional loop

Dear S-news,
 
I want to create a vector of 0's and 1's whose elements are conditional on the previous element.  I start with a vector with 10 elements, the first of which is a 1.  After that I want the following elements to be 1 with probability 0.94.  If any element becomes a 0, then all succeeding elements should be 0.  I wrote the following which gave me fits trying to figure out why it doesn't work.  I don't get any error messages, it just doesn't change my 'fallen' vector. 
 
fallen<-c(1,rep(0,9))
for (i in 2:10) ifelse(fallen[i-1]==1,fallen[i]<-runif(1)<0.94,fallen[i]<-0)   
 
Then I tried it in R.  It worked perfectly.  Can anyone tell me why it doesn't work in S+, please?
 
Many thanks,
 
Manuela

>::<>::<>::<>::<>::<>::<>::<>::<>::<>::<
Manuela Huso
Consulting Statistician
Department of Forest Science
201H Richardson Hall
Oregon State University
Corvallis, OR   97331
ph: 541.737.6232
fx: 541.737.1393

 
<Prev in Thread] Current Thread [Next in Thread>