Andy
Andy

Reputation: 1273

Find the position of first negative number in a R vector that may be entirely positive

Let's say I have a vector drawn from a normal distribution.

RandomVector<-rnorm(10,mean=1,sd=1)
> RandomVector
[1]  1.18186018  0.53810223  0.33888370  0.46593762  2.33963330 -0.08779368     -0.65178144 -0.61384231 -0.74351425
[10] -0.51577616

I want to find the position of the first number <=0 in the vector. The simplest way would be to use which.

FirstNegative<-min(which(RandomVector<=0))

However, in some cases the vector may have no negative numbers, in which case which( ) will return a vector of length zero.

> RandomVector
 [1] 1.20150245 0.58668248 1.65633049 1.63277953 0.51134272 0.76385987 0.89085391 0.06504819 0.18011920 0.02400666

This will give you an error.

> FirstNegative<-min(which(RandomVector<0))
Warning message:
In min(which(RandomVector < 0)) :
  no non-missing arguments to min; returning Inf

Here are some solutions to this problem that I've come up with. All of them work, but I want to avoid an if/else statement if possible. Can anyone think of a more concise way?

for (j in 1:length(RandomVector)) {
        if (RandomVector[j]<=0) {
            FirstNegative<-j
            break;
            }

Alternatively...

WhichNegative<-which(RandomVector<=0)
if (length(WhichNegative)>0) {
    FirstNegative<-min(WhichNegative)
    }

Same basic idea, but still using an if statement

 if (any(RandomVector<=0)==TRUE) {
     FirstNegative<-min(which(RandomVector<=0))
     }

The reason I'm asking is because this check will be made for a large number of vectors of long length. Plus I'm just curious.

Upvotes: 3

Views: 7788

Answers (1)

JCollerton
JCollerton

Reputation: 3317

Solution

You can use:

FirstNegative <- which(RandomVector <= 0)[1]

Which will return the position of the first element less than or equal to zero, or NA if nothing is applicable. You can then catch the NA and do whatever you would like.

Comment

The reason min returns an error is because it expects an input of length greater than zero.

Your first method of searching for the first negative is quite computationally expensive, as you may have to go through every element of the vector. Binomial search may be a quicker method.

The second and third methods are fine, the second will be quicker than the third as in the third you will go through the vector twice, once to find any element less than or equal to zero, then to find the first.

Ultimately though, the method given in solution will be quickest, as which returns a sorted list, and therefore min doesn't do anything useful as the minimum will always be the first element.

Upvotes: 10

Related Questions