Search code examples
rmatrixapply

Can you implement 'sweep' using apply in R?


I'm brushing up on my R skills and finally feel like I've mastered the strange sweep function e.g.

df <- data.frame(a = 1:3, b = 2:4)
sweep(df, MARGIN = 2, STATS = c(5, 10), FUN = "*")

##    a  b
## 1  5 20
## 2 10 30
## 3 15 40

and more usefully here, on a tutorial I'm working on implementing a spatial interaction model in R.

They say that a sign you understand something is that you can say it in many ways, and I think this applies more in programming than almost anywhere else. Yet, despite the problem that sweep solves seeming apply-esque, I have NO IDEA whether they are to some degree interchangeable.

So, in order to improve my own understanding of R, is there any way to do the above procedure using apply?


Solution

  • This is close:

    t(apply(df, 1, `*`, c(5,10)))
    

    The row names are lost but otherwise the output is the same

    > t(apply(df, 1, '*', c(5,10)))
          a  b
    [1,]  5 20
    [2,] 10 30
    [3,] 15 40
    

    To break this down, say we were doing this by hand for the first row of df, we'd write

    > df[1, ] * c(5, 10)
      a  b
    1 5 20
    

    which is the same as calling the '*'() function with arguments df[1, ] and c(5, 10)

    > '*'(df[1, ], c(5, 10))
      a  b
    1 5 20
    

    From this, we have enough to set up an apply() call:

    1. we work by rows, hence MARGIN = 1,
    2. we apply the function '*'() so FUN = '*'
    3. we need to supply the second argument, c(5,10), to '*'(), which we do via the ... argument of apply().

    The only extra thing to realise is how apply() sticks together the vector resulting from each "iteration"; here they are bound column-wise and hence we need to transpose the result from apply() so that we get the same output as sweep().