VaNa
VaNa

Reputation: 367

Alternative to nested ifelse() statements in R

Problem

I need a function which computes uncertainty of measurement by an instrument for different ranges (eg. I measure electrical current and if it's in the range of 2 mA the uncertainty is 0.1 % + 3 dig of the measured value). It is better if the function is able to take a vector and return a vector instead of just numbers.

I have written the function with lots of ifs but it returns warnings the condition has length > 1 and only the first element will be used. After a while of research I have discovered that ifs in R are designed to work with an expression which evaluates to a single boolean value while ifelse can work with vectors.

But as there are about ten chained else ifs the same thing with ifelses would be rather ugly.

Example

with ifs:

S.I = function(I) {
   if(I<=(2*10^(-6))){
      0.1*I/100 + 3*10^(-9)
   } else if(I<=(20*10^(-6))) {
      ...
   }
   ...
}

with ifelses

S.I = function(I) {
   ifelse(I<=(2*10^(-6)),0.1*I/100 + 3*10^(-9),ifelse(I<=(2*10^(-6)),...,ifelse(...)))
}

Question

Is there an alternative to ifelses in this case?

Upvotes: 1

Views: 2012

Answers (2)

Aaron - mostly inactive
Aaron - mostly inactive

Reputation: 37714

The usual way of doing this in R is probably cut; here's an example.

## some sample current values
I <- c(1e-6, 2e-6, 1e-5, 2e-5, 1e-4, 2e-4, 1e-3, 2e-3)
## define the endpoints for the different ranges
breaks <- c(-Inf, 2*10^(-6:3))
## for each range, define the percent of the original
## and the amount to add
percent <- c(0.10, 0.11, 0.12, 0.13)
dig <- c(3e-9, 3e-8, 3e-7, 3e-6) 
## get the range that each value falls in
range <- cut(I, breaks, labels=FALSE)
## and multiply by the right percent and add the right extra amount
I*percent[range]/100 + dig[range]

Upvotes: 3

Math
Math

Reputation: 2436

As you noted, your function only works with single values as if does not act on vectors. The solution is to send each value of your vector one by one to the function.

R provides a set of apply function to do exactly that (it's like a for loop but faster) :

result = sapply(I_vector, S.I)

If you want to apply S.I several times in your code on vectors, it can be worth using a wrapper :

wrapper_S.I = function(I) { return(sapply(I_vector, S.I)) }
result = wrapper_S.I(I_vector)

NOTE: You can also create the wrapper with Vectorize:

wrapper_S.I = Vectorize(S.I)

which creates a wrapper with extra controls.

Upvotes: 1

Related Questions