Kaleb
Kaleb

Reputation: 1022

Update Variable within Loop in R

How should I modify my code to update variables within a loop?

Specifically, I want to do something like the following:

myMatrix1 <- read.table(someFile)
myMatrix2 <- read.table(someFile2)

for (i in nrow(myMatrix2))
{       
    myMatrix3 <- myMatrix1[which(doSomeTest),]
    myMatrix4 <- rep(myMatrix2$header1,nrow(myMatrix1)) 
    myMatrix5 <- rep(myMatrix2$header2, nrow(myMatrix1))        
    myMatrix6 <- cbind(myMatrix3, myMatrix4, myMatrix5) 
    # *see question

}

How can I get myMatrix6 to be updated instead of reassigned the product of cbind(myMatrix3, myMatrix4, myMatrix5)? In other words, if the first iteration (i = 1) gave a myMatrix6 of:

> 1   1    1   1
> 2   2    2   2

and the second iteration (i = 2) gave myMatrix 6 of:

> 3   3    3   3
> 4   4    4   4

how do I get a dataframe(?) of:

> 1   1    1   1
> 2   2    2   2
> 3   3    3   3
> 4   4    4   4

UPDATE:

I have - thanks to DWin and Timo's suggestions - got the following. However, the following code has taken me about 2 hours to run on my datasets. Are there any ways to make it run any faster??? (without using a more powerful computer I may add)

# create empty matrix for sedimentation
myMatrix6 <- data.frame(NA,NA,NA,NA)[0,]
names(myMatrix6) <- letters[1:4]

# create empty matrix for bore
myMatrix7 <- data.frame(NA,NA,NA,NA)[0,]
names(myMatrix7) <- letters[1:4]

for (i in 1:nrow(myMatrix2))
{       
    # create matrix that has the value of myMatrix1$begin being 
    # situated between the values of myMatrix2begin[i] and myMatrix2finish[i]
    myMatrix3 <- myMatrix1[which((myMatrix1$begin > myMatrix2$begin[i]) & (myMatrix1$begin < myMatrix2$finish[i])),]

    myMatrix4 <- rep(myMatrix2$sedimentation, nrow(myMatrix3))

    if (is.na(myMatrix2$boreWidth[i])) {
        myMatrix5 <- rep(NA, nrow(myMatrix3))
    }
    else if (myMatrix2$boreWidth[i] == 0) {
        myMatrix5 <- rep(TRUE, nrow(myMatrix3))
    }
    else if (myMatrix2$boreWidth[i] > 0) {
        myMatrix5 <- rep(FALSE, nrow(myMatrix3))
    }

    myMatrix6 <- rbind(myMatrix6, cbind(myMatrix3, myMatrix4))
    myMatrix7 <- rbind(myMatrix7, cbind(myMatrix3, myMatrix5))
}

Upvotes: 0

Views: 5583

Answers (2)

Timo
Timo

Reputation: 5390

In your code, you are not dealing with matrices (in the sense of R), but data frames, as read.table returns a data frame.

In either way, you can append one matrix/data frame to another (assuming column names match) with rbind command

For example, if

> a = data.frame(x=c(1,2,3),y=c(4,5,6),z=c(7,8,9))
> b = data.frame(x=c(4,5),y=c(5,6),z=c(6,7))

then

> rbind(a,b)
  x y z
1 1 4 7
2 2 5 8
3 3 6 9
4 4 5 6
5 5 6 7

There are other gotchas in the code you provide. For example

for (i in length(someVector)))

should be

for (i in 1:length(someVector)))

R has many functions for iterating over data.frames, vectors etc and can do all kinds of data transformations. Most of the time one does not need to write a for loop.

If you would provide more details about what you are trying to do, maybe we can find a simpler solution.

EDIT:

It seems from your post update that you are trying to do some sort of conversion between 'wide' and 'long' format and filter out some lines that fail a test. Correct me, if I am wrong.

Anyway, if that is the case, you should check out reshape command. Also, there is a reshape package containing extremely useful commands melt and cast, which can do that kind of transformations quite efficiently. Also, there is merge command for doing certain "join" operations for data frames. I'm quite sure your problem could be solved by using a combination of above commands, but it depends on exact details.

For filtering rows/columns with some criteria, check out subset command.

Upvotes: 1

IRTFM
IRTFM

Reputation: 263331

You instead initialize myMatrix6 to an empty data.frame and rbind the results (which may be inefficient). If efficiency is a concern then you pre-allocate to the size you want and fill in rows in the data.frame with indexing.

# Method # 1 code
myMatrix6 <- data.frame(NA,NA,NA,NA)[0,]
names(myMatrix6) <- letters[1:4]

for (i in nrow(myMatrix2)) {       
    myMatrix3 <- myMatrix1[which(doSomeTest),]
    myMatrix4 <- rep(myMatrix2$header1,nrow(myMatrix1)) 
    myMatrix5 <- rep(myMatrix2$header2, nrow(myMatrix1))        
    myMatrix6 <- rbind( myMatrix6, cbind(myMatrix3, myMatrix4, myMatrix5) )
                           }

Upvotes: 2

Related Questions