Tim_Utrecht
Tim_Utrecht

Reputation: 1519

Creating a variable out of a loop in R

I think my question is very very easy for common R users.

Edit: My example is probably a to simplified version of my true problem: See the following code:

library(markovchain)

#create a new MC with transition matrix transitionMatrix
mcStaticPool <- new("markovchain", states=c("perf", "def", "prep"),
                    transitionMatrix=matrix(data=c(0.89715, 0.01475, 0.08810, 0, 1, 0, 0, 0, 1), 
                                            byrow=TRUE, nrow=3), name="StaticPool")
#display transition matrix
#print(mcStaticPool)
show(mcStaticPool)

#initially all loans are performing
initialState<-c(1,0,0)
nYears<-10

for(i in 1:nYears){
  afterNYears<-initialState*(mcStaticPool^i)
   print(afterNYears) 
}

I want this in a vector. And actually only the numbers. not the states.

        perf     def   prep
[1,] 0.89715 0.01475 0.0881
          perf        def      prep
[1,] 0.8048781 0.02798296 0.1671389
          perf        def      prep
[1,] 0.7220964 0.03985491 0.2380487
          perf        def      prep
[1,] 0.6478288 0.05050584 0.3016654
          perf        def      prep
[1,] 0.5811996 0.06006131 0.3587391
          perf        def      prep
[1,] 0.5214232 0.06863401 0.4099428
          perf      def      prep
[1,] 0.4677948 0.076325 0.4558802
          perf        def      prep
[1,] 0.4196821 0.08322497 0.4970929
          perf        def      prep
[1,] 0.3765178 0.08941528 0.5340669
         perf        def      prep
[1,] 0.337793 0.09496892 0.5672381

The following loop:

for(i in 1:10){
  test<-2*(2^i)
  print(test) 
}

This gives:

[1] 4
[1] 8
[1] 16
[1] 32
[1] 64
[1] 128
[1] 256
[1] 512
[1] 1024
[1] 2048

I want to save this as a variable, for example called test2.

I tried this:

for(i in 1:10){
  test<-2*(2^i)
  test2 <- print(test) 
}

But then it gives:

> test2
[1] 2048

But I want the entire sequence in test2:

[1] 4
[1] 8
[1] 16
[1] 32
[1] 64
[1] 128
[1] 256
[1] 512
[1] 1024
[1] 2048

Thanks, Best regards,

Tim

Upvotes: 0

Views: 222

Answers (3)

Greg Snow
Greg Snow

Reputation: 49660

As others have mentioned, you can just vectorize this, but if you are doing something more complicated that does not vectorize like this then there are other options.

When your main goal is to create a vector (or matrix or array) based on the result of each iteration then it is usually better/simpler/clearer/etc. to use the sapply function (or other related functions) rather than an explicit loop.

for example:

test2 <- sapply(2:11, function(x) 2*(2^i))

If you really need a loop then it is best to preallocate a vector (or matrix, array, list, etc.) and assign into the vector (or other structure).

Here is some benchmarking to compare the methods (I have increased the iterations to make the difference clearer):

> library(microbenchmark)
> 
> out <- microbenchmark( 
+   bad={test2 <- NULL; for(i in 1:10000) test2 <- c(test2,2*(2^i))},
+   good={test2 <- numeric(10000); for(i in 1:10000) test2[i] <- 2*(2^i) },
+   better={test2=sapply(1:10000, function(x) 2*(2^x))},
+   best={test2=2*(2^(1:10000))} )
> out
Unit: microseconds
   expr        min          lq     median         uq        max neval
    bad 172508.454 174738.8165 176630.910 197765.369 211581.875   100
   good  26387.491  27683.0960  28150.475  28567.769  52588.194   100
 better  20645.118  21288.8155  22140.853  23022.652  49513.799   100
   best    719.234    763.1595    768.086    773.628   1622.381   100
> plot(out)
> 

Upvotes: 1

nico
nico

Reputation: 51680

General rule: if you find yourself using a for loop in R you are most likely on the wrong route ;)

Vectorize when possible

test <- 2^2:11

If you insist in using a for loop you should do

test <- NULL
for (i in 2:11)
    test <- c(test, 2^i)

or, to avoid allocating memory each time

test <- numeric(10)
for (i in 1:10)
    test[i] <- 2^(i+1)

Your code ends up with only the 2048 value as you are overwriting test each time with a single value, and not concatenating the other powers of 2 as you go.

Upvotes: 1

Juli&#225;n Urbano
Juli&#225;n Urbano

Reputation: 8488

You should simply do this:

test2 <- 2^(2:11)

or test2 <- 2*2^(1:10) or test2 <- 2^(1:10+1), whichever shows better what you're trying to do.

But if you really want to use a loop, do this:

test2 <- numeric(10)
for(i in 1:length(test2)) {
  test2[i] <- 2*(2^i)
}

Upvotes: 2

Related Questions