Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a function like rollapply for data.frame [duplicate]

Tags:

r

Possible Duplicate:
Can `ddply` (or similar) do a sliding window?

Is there a function like rollapply (standard R or within a CRAN package) that operates on a data.frame, but doesn't convert it to a matrix. rollapply can be used with a data.frame, but if the data.frame has mixed types then each window of data is converted to a character (matrix).

I prefer a function that supports width, na.pad, align, etc. just like rollapply

Example

Take any data.frame with mixed-types

test = data.frame( Name = c( "bob" , "jane" , "joe" ) , Points = c( 4 , 9 , 1 ) )

Lets say you want to roll with window size 2. The first iteration of FUN is called with a data.frame that only includes rows 1 and 2 of test.

So RollapplyThatRespectsDataFrame( ... , FUN = function( x ) { ... } ) upon the first iteration would set x = data.frame( Name = c( "bob" , "jane" ) , Points = c( 4 , 9 ) )

The second iteration is a data.frame with rows 2 and 3 of test.

Basically this new function does the same thing as rollapply, except it works properly with data.frames. It doesn't convert to matrix.

like image 545
SFun28 Avatar asked Dec 07 '12 21:12

SFun28


1 Answers

Try this:

> library(zoo)
> DF <- data.frame(a = 1:10, b = 21:30, c = letters[1:10])
> replace(DF, 1:2, rollapply(DF[1:2], 3, sum, fill = NA))
    a  b c
1  NA NA a
2   6 66 b
3   9 69 c
4  12 72 d
5  15 75 e
6  18 78 f
7  21 81 g
8  24 84 h
9  27 87 i
10 NA NA j

Regarding the example that was added to the question after some discussion, such functionality can be layered on top of rollapply by applying it to the row indexes:

> lapply(as.data.frame(t(rollapply(1:nrow(test), 2, c))), function(ix)test[ix, ])
$V1
  Name Points
1  bob      4
2 jane      9

$V2
  Name Points
2 jane      9
3  joe      1

and here it is wrapped up a bit better:

rollapply.data.frame <- function(data, ..., fill = NULL, FUN, 
        simplify = function(x) do.call(rbind, x)) {
    fill0 <- if (!is.null(fill)) NA
    result <- lapply(
       as.data.frame(t(rollapply(1:nrow(data), ..., fill = fill0, FUN = c))), 
       function(ix) {if (all(is.na(ix))) fill else FUN(data[ix, ])}
    )
    simplify(result)
}

> rollapply(test, 2, FUN = identity, simplify = identity)
$V1
  Name Points
a  bob      4
b jane      9

$V2
  Name Points
b jane      9
c  joe      1

> rollapply(test, 2, FUN = identity, fill = NA, simplify = identity)
$V1
  Name Points
a  bob      4
b jane      9

$V2
  Name Points
b jane      9
c  joe      1

$V3
[1] NA
like image 147
G. Grothendieck Avatar answered Sep 29 '22 14:09

G. Grothendieck