[R] Carrying a value down a data.frame conditionally

peter dalgaard pdalgd at gmail.com
Wed Dec 24 10:35:13 CET 2014

> On 23 Dec 2014, at 23:57 , Pooya Lalehzari <plalehzari at platinumlp.com> wrote:
> Hello,
> I have a data.frame (below) containing the two fields of "Value" and "Signal" and I would need to create the third field of "To_Be_Produced". The condition for producing the third field is to carry the 1 in the "Signal" field down until "Value" is below 40.
> Do I have to create a for-loop to do this or will I be able to do anything else more efficient?
> df <- data.frame( Value=c(0,0,100,85,39,1,30,40,20,20,0,0),
>                  Signal=c(0,1,0,0,0,0,0,0,0,1,0,0),
>                  To_Be_Produced= c(0,1,1,1,0,0,0,0,0,1,0,0)
>                )

I'd go with the for loop, unless you _really_ need the efficiency. And if you do need efficiency that badly, it is probably better to code up the for loop in C/C++. (An Rcpp evangelist is likely to chime in any moment now.)

If you want a vectorized solution just for the academic exercise, I think you can do something with ave(), grouping by cumsum(Signal) and within groups doing cumprod(Value >= 40), except that you need to skip the first element of each group. And be careful that the first group is different.

This seems to do it:

> with(df, ave(Value, cumsum(Signal), FUN=function(x) c(0,cumprod(x[-1]>=40))
              ) + Signal)
 [1] 0 1 1 1 0 0 0 0 0 1 0 0

Peter Dalgaard, Professor,
Center for Statistics, Copenhagen Business School
Solbjerg Plads 3, 2000 Frederiksberg, Denmark
Phone: (+45)38153501
Email: pd.mes at cbs.dk  Priv: PDalgd at gmail.com

More information about the R-help mailing list