Reputation:
I have a vector x,y
and data frame df
such that
NCOL(x) = NCOL(y) = ncol(df).
I would like to divide each columns (all rows) by vector x
(it means: all values in column one of df
by the fist values in vector x
, second column (all values) by second column (one value) of vector x
.
The same situation for adding vector y
to columns (the same way).
Could you help me do it in elegant way ?
Upvotes: 4
Views: 465
Reputation: 35314
An alternative is to transpose, perform the operations taking advantage of automatic recycling of the short vector operands, and then transpose again to return to the original transposition. This solution results in a matrix rather than a data.frame, which may not be desirable, although it can be argued that since you're performing a numerical computation on every cell of the input, it's more appropriate to store it as a numeric matrix.
Stealing akrun's data for an example:
df <- as.data.frame(matrix(1:25,5L,5L));
x <- 1:5;
y <- 6:10;
t(t(df)/x + y);
## V1 V2 V3 V4 V5
## [1,] 7 10.0 11.66667 13.00 14.2
## [2,] 8 10.5 12.00000 13.25 14.4
## [3,] 9 11.0 12.33333 13.50 14.6
## [4,] 10 11.5 12.66667 13.75 14.8
## [5,] 11 12.0 13.00000 14.00 15.0
This solution seems to have a performance benefit:
library(microbenchmark);
akrun <- function() df/x[col(df)] + y[col(df)];
bgoldst <- function() t(t(df)/x + y);
identical(as.data.frame(bgoldst()),akrun());
## [1] TRUE
identical(bgoldst(),as.matrix(akrun()));
## [1] TRUE
identical(bgoldst(),akrun());
## [1] FALSE
microbenchmark(akrun(),bgoldst(),times=1000L);
## Unit: microseconds
## expr min lq mean median uq max neval
## akrun() 812.542 867.9235 930.60749 894.6515 922.235 2395.288 1000
## bgoldst() 50.036 58.5890 68.82336 67.1420 71.846 1417.672 1000
I've given akrun +1 for my thievery.
Upvotes: 1
Reputation: 887128
We can replicate 'x' and then divide the 'df'
df/x[col(df)]
If we need to add 'y'
(df/x[col(df)]) + y[col(df)]
df <- as.data.frame(matrix(1:25, 5, 5))
x <- 1:5
y <- 6:10
Upvotes: 3