Avoiding 'while' loop in R - r

I'm wondering, whether it is possible to omit 'while' loop in this part of R code?
while (matrix[i] != -1){
i = i+1
}
Thanks!

You can use:
i <- which(a==-1)[1]
which(a==-1) returns all the indices of the elements of the vector or matrix a which are equal to -1. You only want the first one, so take element 1 of the resulting array.
Note: this returns NA if the matrix a does not have any -1 element

Related

Compare values between vectors of unequal size to find values within a certain distance of each other (without loops?)

I have two vectors of unequal length full of numbers in R. I want to find all instances of vector 1 where the value is within 0.0015 of any value in vector 2, and then delete those instances out of vector 1. Is there a good way to do this without doing nested for loops? It's inefficient and is slowing my program down.
Currently I am iterating through the first vector and comparing each instance to every value from the second vector and I'm looking for an alternate approach. See below:
I have a vector called tracker, which by default is true, but will turn false if there is a value in the second vector that is closer than 0.0015 to the value of interest in the first vector. This tracker vector is my desired output, because as you can see at the bottom, I use it to filter a different vector.
tracker <- rep(TRUE,length = length(filteredMZunrounded))
for(i in 1:length(filteredMZunrounded)){
for(j in 1:length(bg.unrounded)){
if(abs(filteredMZunrounded[i]-bg.unrounded[j]) < 0.0015){
tracker[i] <- FALSE
}
}
}
filteredMZ <- filteredMZ[tracker]
You can remove the inner loop :
tracker <- rep(TRUE,length = length(filteredMZunrounded))
for(i in 1:length(filteredMZunrounded)){
if(any(abs(filteredMZunrounded[i]-bg.unrounded) < 0.0015)) {
tracker[i] <- FALSE
}
}
}
filteredMZ <- filteredMZ[tracker]

How to write a function for and for loop with embedded if else statement?

I have just started using R for a course I'm taking and it asked for integer values > 0 (argument1) and which will multiply values <25 and >75 by a set multiplier (argument 2) and the other elements by a different multiplier (argument 3).
I already have the previous h and s values:
h=sample(1:100,40)
s=c()
for(i in 1:100){if(h[i]<25){s[i]<-h[i]*10}
else if(h[i]>75){s[i]<-h[i]*10}
else{s[i]<-h[i]*0.1}}
Error in if (h[i] < 25) { : missing value where TRUE/FALSE needed
The error message shows up in the above for loop but if I ignore it I still get the answer. I want but would not work in the function.
fun2<-function(x=s,arg1,arg2,arg3)
{w<-for(i in 1:100){if(h[i]>0){s[i]<-h[i]*arg1}else if(h[i]<25){s[i]<-
h[i]*arg2}
else if(h[i]>75){s[i]<-h[i]*arg2}
else{s[i]<-h[i]*arg3}}
return(w)}
fun2(arg1=10,arg2=3,arg3=10)
Error in if (h[i] > 0) { : missing value where TRUE/FALSE needed
I am unsure where to put the true/false statement in the equation.
Take a look at length(h).
You'll see that you are trying to loop over 100 indexes while having only 40 elements. If you replace your first line by h = sample(1:100,100), your first code should work.
As for your second attempt, you cannot assign a for-loop to a variable. Store your variable w before looping and the assign the new values that you are calculating, like this.
fun2<-function(x=s,arg1,arg2,arg3){
w<-s
for(i in 1:100){
if(h[i]>0){
w[i]<-h[i]*arg1
}
... # some if statement
return(w)
}
As a side note, your function won't give you the results you are looking for because your first if condition discards the following else if. I would remove the first if block and replace the next one by if(h[i] < 25 & h[i]> 0).

indexing in loops: var[x+1] subscript out of bounds

I'm creating and storing a bunch of conditional matrices in vector form then I'm recalling them, returning their structure to matrix, and multiplying by a vector. This vector depends on the previous vector and the current matrix. I have tried to express this in the second loop as [,y+1] to index the vectors on the output matrix . While I get the desire result, I also get an error that aborts the program. I would appreciate suggestions on how to approach this.
env=rnorm(50, 22, 5)
les=matrix(nrow=9,ncol=length(env),byrow=T)
for (x in 1:length(env))
{
a=sqrt(env[x])-3
b=sqrt(env[x])-2
c=sqrt(env[x])-1
A=.9
B=.5
C=.2
les[,x]=c(a,b,c,A,0,0,0,B,0)
}
pop=matrix(nrow=3,ncol=length(env))
pop[,1]=c(1,2,2)
for (y in 1:length(env))
{
pop[,y+1]=pop[,y]%*%matrix(les[,y],3,3,T)
}
print(pop)
barplot(pop)
Vector, matrix and array subscripting in R is all 1-based. You need to iterate only up to length(env)-1 if you are going to regerence ahead by 1 inside the loop.

if statement in r?

I am not sure what I am doing wrong here.
ee <- eigen(crossprod(X))$values
for(i in 1:length(ee)){
if(ee[i]==0:1e^-9) stop("singular Matrix")}
Using the eigen value approach, I am trying to determine if the matrix is singular or not. I am attempting to find out if one of the eigen values of the matrix is between 0 and 10^-9. How can I use the if statement (as above) correctly to achieve my goal? Is there any other way to approach this?
what if I want to concatenate the zero eigen value in vector
zer <-NULL
ee <- eigen(crossprod(X))$values
for(i in 1:length(ee)){
if(abs(ee[i])<=1e-9)zer <- c(zer,ee[i])}
Can I do that?
#AriBFriedman is quite correct. I can, however see a couple of other issues
1e^-9 should be 1e-9.
0:1e-9 returns 0, (: creates a sequence by one between 0 and 1e-9, therefore returns just 0. See ?`:` for more details
Using == with decimals will cause problems due to floating point arithmetic
In the form written, your code checks (individually) whether the elements ee[i] == 0, which is not what you want (nor does it make sense in terms floating point arithmetic)
You are looking for cases where the eigen value is less than this small number, so use less than (<).
What you are looking for is something like
if(any(abs(ee) < 1e-9)) stop('singular matrix')
If you want to get the 0 (or small) eigen vectors, then use which
# this will give the indexs (which elements are small)
small_values <- which(abs(ee) < 1e-9))
# and those small values
ee[small_values]
There is no need for the for loop as everything being done is vectorized.
if takes a single argument of length 1.
Try either ifelse or using any() or all() to turn your vector of logicals into a logical vector of length 1.
Here's an example reproducing your data:
X <- matrix(1:10,1:10)
ee <- eigen(crossprod(X))$values
This will test if any of the values of ee are > 0 AND< 1e-9
if (any((ee > 0) & (ee < 1e-9))) {stop("singular matrix")}

missing value where TRUE/FALSE needed error in R

I have got a column with different numbers (from 1 to tt) and would like to use looping to perform a count on the occurrence of these numbers in R.
count = matrix(ncol=1,nrow=tt) #creating an empty matrix
for (j in 1:tt)
{count[j] = 0} #initiate count at 0
for (j in 1:tt)
{
for (i in 1:N) #for each observation (1 to N)
{
if (column[i] == j)
{count[j] = count[j] + 1 }
}
}
Unfortunately I keep getting this error.
Error in if (column[i] == j) { :
missing value where TRUE/FALSE needed
So I tried:
for (i in 1:N) #from obs 1 to obs N
if (column[i] = 1) print("Test")
I basically got the same error.
Tried to do abit research on this kind of error and alot have to said about "debugging" which I'm not familiar with.
Hopefully someone can tell me what's happening here. Thanks!
As you progress with your learning of R, one feature you should be aware of is vectorisation. Many operations that (in C say) would have to be done in a loop, can be don all at once in R. This is particularly true when you have a vector/matrix/array and a scalar, and want to perform an operation between them.
Say you want to add 2 to the vector myvector. The C/C++ way to do it in R would be to use a loop:
for ( i in 1:length(myvector) )
myvector[i] = myvector[i] + 2
Since R has vectorisation, you can do the addition without a loop at all, that is, add a scalar to a vector:
myvector = myvector + 2
Vectorisation means the loop is done internally. This is much more efficient than writing the loop within R itself! (If you've ever done any Matlab or python/numpy it's much the same in this sense).
I know you're new to R so this is a bit confusing but just keep in mind that often loops can be eliminated in R.
With that in mind, let's look at your code:
The initialisation of count to 0 can be done at creation, so the first loop is unnecessary.
count = matrix(0,ncol=1,nrow=tt)
Secondly, because of vectorisation, you can compare a vector to a scalar.
So for your inner loop in i, instead of looping through column and doing if column[i]==j, you can do idx = (column==j). This returns a vector that is TRUE where column[i]==j and FALSE otherwise.
To find how many elements of column are equal to j, we just count how many TRUEs there are in idx. That is, we do sum(idx).
So your double-loop can be rewritten like so:
for ( j in 1:tt ) {
idx = (column == j)
count[j] = sum(idx) # no need to add
}
Now it's even possible to remove the outer loop in j by using the function sapply:
sapply( 1:tt, function(j) sum(column==j) )
The above line of code means: "for each j in 1:tt, return function(j)", an returns a vector where the j'th element is the result of the function.
So in summary, you can reduce your entire code to:
count = sapply( 1:tt, function(j) sum(column==j) )
(Although this doesn't explain your error, which I suspect is to do with the construction or class of your column).
I suggest to not use for loops, but use the count function from the plyr package. This function does exactly what you want in one line of code.

Resources