Jesse
Jesse

Reputation: 244

Using multiple rows in a mapply call

This seems like a straightforward problem, but I'm having trouble finding a solution here on Stack Overflow. I have a data frame df with columns of data a and b. I have a complex function (simplified example below) that I want to apply to all rows using mapply. The problem I'm having is that I want to take an average of the n and n-1 rows of b as an input into the function, in place of b. Here is an example

new.fun  <- function( a, b ) { a * b } 
a        <- seq( from = 1, to = 10, by = 1 )
df       <- data.frame( a , b = a * 10 ) 
mapply( new.fun, df$a, df$b )

Short of making a new column with the average of n and n-1 (something that I only know how to do with a for loop) and using that as an input, or creating a for loop, is there a way to do this in a more "R-like" manner?

EDIT: Sorry, I forgot to add in the expected answer for the above example. The averages of b[1:2], b[2:3], etc. should be:

 b2   <- c( 0, seq( from = 15, to = 95, by = 10 ) )

EDIT2: Had the wrong number of terms in here....set first term to 0 for these purposes

And the solution to the whole question should be:

> new.fun( df$a, b2 )
 [1]   0  30  75 140 225 330 455 600 765 950

Sorry for the confusing series of posts here. Apparently I'm not describing the problem precisely. I want one variable within my mapply call to consist not of the value in a particular row of the column within df, but of an average of the nth row and the n-1 row, basically a moving average of the row and preceding row, but I'm wondering if it can be packaged within the mapply call in some clever way?

Upvotes: 0

Views: 85

Answers (3)

Ronak Shah
Ronak Shah

Reputation: 388982

We can use rollmean from zoo package to calculate the rolling mean for b column and then multiply it with a column. (Similar to what @Sotos mentioned in comments.)

library(zoo)
df$a * c(0, rollmean(df$b, 2))

#[1]  0 30  75 140 225 330 455 600 765 950

Or by using the mapply function

mapply(new.fun, df$a, c(0, rollmean(df$b, 2))

Upvotes: 0

Hong Ooi
Hong Ooi

Reputation: 57686

zoo::rollapply is a very heavyweight (and slow) solution to a lightweight problem.

with(df, {
    bmean <- c(NA, (b[-1] + b[-length(b)])/2)  # replace NA with desired initial value
    mapply(new.fun, a, bmean)
})

Upvotes: 2

user3603486
user3603486

Reputation:

lapply(seq(2, nrow(df)), function (i) {
  mean_a <- mean(df$a[(i-1):i])
  mean_b <- mean(df$b[(i-1):i])
  new.fun(mean_a, mean_b)
})

You could use sapply if you know the length of output your function is going to produce.

See also zoo::rollapply.

Upvotes: 1

Related Questions