Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to apply a function to each element of a vector in R

Tags:

r

vector

apply

Let's say I want to multiply each even element of a vector by 2 and each odd element of a vector by 3. Here is some code that can do this:

v <- 0:10

idx <- v %% 2 == 0
v[idx] <- v[idx] * 2
v[!idx] <- v[!idx] * 3

This would get difficult if I had more than two cases. It seems like the apply family of functions never deals with vectors so I don't know a better way to do this problem. Maybe using an apply function would work if I made transformations on the data, but it seems like that shouldn't be something that I would need to do to solve this simple problem.

Any ideas?

Edit: Sorry for the confusion. I am not specifically interested in the "%%" operator. I wanted to put some concrete code in my question, but, based on the responses to the question, was too specific. I wanted to figure out how to apply some arbitrary function to each member of the list. This was not possible with apply() and I thought sapply() only worked with lists.

like image 739
dubois Avatar asked Jan 08 '13 00:01

dubois


4 Answers

You can do:

v <- v * c(2, 3)[v %% 2 + 1]

It is generalizable to any v %% n, e.g.:

v <- v * c(2, 3, 9, 1)[v %% 4 + 1]

Also it does not require that length(v) be a multiple of n.

like image 133
flodel Avatar answered Oct 06 '22 08:10

flodel


You can use vector multiplication to do what you want:

tmp <- 1:10
tmp * rep(c(3,2), length(tmp)/2)

This is easy to extend to three or more cases:

tmp * rep(c(3,2,4), length(tmp)/3)
like image 42
Tyler Avatar answered Oct 06 '22 10:10

Tyler


Easiest would be:

v*c(2,3) # as suggested by flodel in a comment.

The term to search for in the documentation is "argument recycling" ... a feature of the R language. Only works for dyadic infix functions (see ?Ops). For non-dyadcic vectorized functions that would not error out with some of the arguments and where you couldn't depend on the structure of "v" to be quite so regular, you could use ifelse:

ifelse( (1:length(v)) %% 2 == 0, func1(v), func2(v) )

This constructs two vectors and then chooses elements in the first or second based on the truth value of hte first argument. If you were trying to answer the question in the title of your posting then you should look at:

?sapply
like image 28
IRTFM Avatar answered Oct 06 '22 10:10

IRTFM


Here is an answer allowing any set of arbitrary functions to be applied to defined groups within a vector.

# source data
test <- 1:9
# categorisations of source data
cattest <- rep(1:3,each=3)
#[1] 1 1 1 2 2 2 3 3 3

Make the function to differentially apply functions:

categ <- function(x,catg) {
          mapply(
                 function(a,b) {
                                switch(b,
                                       a * 2,
                                       a * 3,
                                       a / 2
                                      )
                               },
                  x,
                  catg
                 )
         }
# where cattest = 1, multiply by 2
# where cattest = 2, multiply by 3
# where cattest = 3, divide by 2

The result:

categ(test,cattest)
#[1]  2.0  4.0  6.0 12.0 15.0 18.0  3.5  4.0  4.5
like image 38
thelatemail Avatar answered Oct 06 '22 08:10

thelatemail