Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use a vectorised function in R in alternate sequence?

Tags:

r

modulo

sequence

Suppose I have a vector x with n elements. I want to use any vectorised function, say cumprod, on every alternate number of x, i.e. every 1, 3, 5 and so on and another on 2, 4, 6 and so on. I am adding a reprex and code tried. The code works, but it seems I am unnecessarily taking a long route and code can be shortened. Can it be?

x <- 5:14

cumprod((x * (seq_along(x) %% 2)) + (seq_along(x)-1) %% 2) * seq_along(x) %% 2 +
  cumprod((x * ((seq_along(x)-1) %% 2)) + seq_along(x) %% 2) * (seq_along(x)-1) %% 2
#>  [1]     5     6    35    48   315   480  3465  5760 45045 80640

Here cumprod is just an example function. I may have to use other functions in alternate sequence as well.

like image 865
AnilGoyal Avatar asked Jul 28 '21 16:07

AnilGoyal


People also ask

How do I apply a function to a list in R?

lapply() function in R Programming Language is used to apply a function over a list of elements. lapply() function is used with a list and performs the following operations: lapply(List, length): Returns the length of objects present in the list, List.

What is advantage of using apply family of functions in R?

Functions present in the apply family are the ones that allow us to manipulate data frames, arrays, matrices, vectors. These functions are alternative to the loops. However, are more efficient than loops as functions are faster at the execution level. These functions reduce the need for explicitly creating a loop in R.

How do I sum multiple vectors in R?

The sum() is a built-in R function that calculates the sum of a numeric input vector. It accepts a numeric vector as an argument and returns the sum of the vector elements. To calculate the sum of vectors in R, use the sum() function.


3 Answers

We could do this in a concise way with rowCumprods after creating a matrix (assuming the vector is of even length)

library(matrixStats)
c(rowCumprods(matrix(x, nrow = 2)))

-output

[1]     5     6    35    48   315   480  3465  5760 45045 80640

if it can be odd length, then just append an NA at the end

 c(rowCumprods(matrix(c(x,  list(NULL, NA)[[1 +
         (length(x) %%2 != 0)]]), nrow = 2)))

-output

 [1]     5     6    35    48   315   480  3465  5760 45045 80640

Or we can do this in a generalized way with ave (works both with even/odd lengths)

ave(x, seq_along(x) %% 2, FUN = cumprod)
 [1]     5     6    35    48   315   480  3465  5760 45045 80640
like image 88
akrun Avatar answered Oct 18 '22 07:10

akrun


Select odd (c(TRUE, FALSE)) or even (c(FALSE, TRUE)) indices. Weave the two resulting vectors (c(rbind)

c(rbind(cumprod(x[c(TRUE, FALSE)]), cumprod(x[c(FALSE, TRUE)])))
# [1]     5     6    35    48   315   480  3465  5760 45045 80640

To handle also odd vector length, you need to truncate the result to length of the vector.

x = 1:5

c(rbind(cumprod(x[c(TRUE, FALSE)]), cumprod(x[c(FALSE, TRUE)])))[1:length(x)]
# [1]  1  2  3  8 15

There will be a warning when the shorter result vector, corresponding to the even indices (which has one element less), is recycled in the rbind step.

like image 7
Henrik Avatar answered Oct 18 '22 07:10

Henrik


One option for both even and odd number of elements could be:

c(t(apply(matrix(x, 2, sum(seq_along(x) %% 2)), 1, cumprod)))[1:length(x)]

With x <- 1:5:

[1]  1  2  3  8 15

With x <- 1:6:

[1]  1  2  3  8 15 48

Or a less effective option, however, without any warnings:

y <- Reduce(`c`, sapply(split(setNames(x, seq_along(x)), !seq_along(x) %% 2), cumprod))
y[order(as.numeric(names(y)))]
like image 6
tmfmnk Avatar answered Oct 18 '22 05:10

tmfmnk