Reputation: 1021
I was writing up notes to compare apply() and sweep() and discovered the following strange differences. In order the generate the same result, sweep() needs MARGIN = 1 while apply wants MARGIN = 2. Also the argument specifying the matrix is uppercase X in apply() but lowercase in sweep().
my.matrix <- matrix(seq(1,9,1), nrow=3)
row.sums <- rowSums(my.matrix)
apply.matrix <- apply(X = my.matrix, MARGIN = 2, FUN = function (x) x/row.sums)
sweep.matrix <- sweep(x = my.matrix, MARGIN = 1, STATS = rowSums(my.matrix), FUN="/")
apply.matrix - sweep.matrix ##yup same matrix
Isn't sweep() an "apply-type" function? Is this just another R quirk or have I lost my mind?
Upvotes: 4
Views: 3542
Reputation: 498
I'd like to disaggree with Weihuang Wong.
Let's illustrate it with a simpler example, (using a non-square matrix as he suggests):
(A = matrix(1:12, 3)) # Non-Square Matrix
(B=sweep(A, MARGIN=1, 1:3, FUN='/')) # only difference is margin
(C=apply(A, MARGIN=2, 1:3, FUN='/')) # only difference is margin
all.equal(B, C) # they're equal, but margins are opposite
If you were to try the transpose and same margins he suggested:
(A = matrix(1:12, 3)) # Non-Square Matrix
(B=sweep(A, MARGIN=1, 1:3, FUN='/'))
(C=t(apply(A, MARGIN=1, 1:3, FUN='/'))) # warning saying 'shapes don't match'
all.equal(B, C) # not equal, transposing doesn't work
I said basically the same thing here: An intuitive way to understand MARGIN in sweep and apply
P.S. I usually use sweep for broadcasting (e.g. like numpy), if you want consistent behavior you could probably just use apply like I demonstrated.
Upvotes: 0
Reputation: 13128
Note that for apply
,
If each call to ‘FUN’ returns a vector of length ‘n’, then ‘apply’ returns an array of dimension ‘c(n, dim(X)[MARGIN])’ if ‘n > 1’
In your example, MARGIN
can (and should) be set to 1
in both cases; but the returned value from apply
should be transposed. This is easiest to see if the original matrix is not square:
my.matrix <- matrix(seq(1,12,1), nrow=4)
apply.matrix <- t(apply(X = my.matrix, MARGIN = 1, FUN = function(x) x/sum(x)))
sweep.matrix <- sweep(x = my.matrix, MARGIN = 1, STATS = rowSums(my.matrix), FUN="/")
all.equal(apply.matrix, sweep.matrix)
# [1] TRUE
Also see this answer to Can you implement 'sweep' using apply in R?, which says very much the same thing.
Upvotes: 6