ktj1989
ktj1989

Reputation: 807

R Vectorizing Operation

I would like to take each element of a column of a dataframe (a number), corece it into a vector by multiplying it by a vector to get a vector, and then multiplying it by each row in a dataframe.

The code is as follows:

df = data.frame(matrix(rexp(1441*100, rate=.1), ncol=100))

out_vec <- c()
for (i in 1:nrow(df)) {


  out_vec[i]<- sum(df[i, 5:100] * (1 + abs(df$X1[i])/100) ^ -(0:95 / 12))

}

How can i vectorize this code? I have tried

out_vec_alt <- rowSums(df[, 5:100] * (1 + abs(df$X1)/100) ^ -(0:95 / 12))

but it is not producing the desired result:

all(out_vec_alt == out_vec) #FALSE

Upvotes: 1

Views: 30

Answers (1)

IceCreamToucan
IceCreamToucan

Reputation: 28675

The second part needs to be done with outer. You can use a^b in a vectorized way, but it will not apply the operation to the first element of a vs all elements of b, the the second element of a vs all elements of b, etc., like you want in this case. It will just give c(a[1]^b[1], a[2]^b[2], ..., a[n]^b[n]).

out_vec2 <- rowSums(df[5:100] * outer(1 + abs(df$X1)/100, -(0:95)/12, `^`))

all.equal(out_vec, out_vec2)
# [1] TRUE

Obviously this will be faster, but I was surprised to see it's >200x faster (at median time) for this example

loop <- function(){
  out_vec <- c()
  for (i in 1:nrow(df)) {
    out_vec[i]<- sum(df[i, 5:100] * (1 + abs(df$X1[i])/100) ^ -(0:95 / 12))
  }
  out_vec
}

vect <- function() rowSums(df[5:100] * outer(1 + abs(df$X1)/100, -(0:95)/12, `^`))

library(microbenchmark)
microbenchmark(loop(), vect(), times = 10)
# Unit: milliseconds
#    expr         min          lq        mean      median          uq        max neval
#  loop() 12065.34780 12756.12062 13095.97435 12892.87818 13460.56978 15030.0197    10
#  vect()    35.73011    41.36212    60.57327    54.40029    79.25182   104.0453    10

Upvotes: 3

Related Questions