loop to create several matrix in R (maybe using paste)

13,480

Solution 1

You need assign:

for (i in 1:27) {
  assign(paste("x",i,sep=""), cbind(rep(1,aux[i]), rnorm(aux[i])))
}

This will create 27 matrix objects in your global environment.

Solution 2

If you need different number of rows then you definitely need to use a list. See the example below:

First, declaring your aux variable which holds the number of rows to generate:

aux <- 50:77

And let your loop spin:

x <- vector("list",27) 
for (i in 1:27) {
    x[[i]] <- cbind(rep(1,aux[i]), rnorm(aux[i]))
}

Which will give back the list of your data frames. See e.g. str(x) for the list and str(x[[1]]) for the first matrixe's structure. The latter would return:

 num [1:50, 1:2] 1 1 1 1 1 1 1 1 1 1 ...

And you are right: it could be written a lot nicer than this proposal, look for lapply and so, but others will help you out with that tricky part :)


After editing: added lapply example

Try the code below if you are familiar with the above loop (and of course look for ?lapply):

aux <- 50:77
fun <- function(x) cbind(rep(1,x), rnorm(x))
x <- lapply(aux, fun)

Solution 3

If you have nothing against lists, here's another shot at your question:

aux <- 30:40
manoel <- sapply(aux, function(x) {
            matrix(NA, ncol = 2, nrow = x)
        }, simplify = FALSE)

> str(manoel)
List of 11
 $ : logi [1:30, 1:2] NA NA NA NA NA NA ...
 $ : logi [1:31, 1:2] NA NA NA NA NA NA ...
 $ : logi [1:32, 1:2] NA NA NA NA NA NA ...
 $ : logi [1:33, 1:2] NA NA NA NA NA NA ...
 $ : logi [1:34, 1:2] NA NA NA NA NA NA ...
 $ : logi [1:35, 1:2] NA NA NA NA NA NA ...
 $ : logi [1:36, 1:2] NA NA NA NA NA NA ...
 $ : logi [1:37, 1:2] NA NA NA NA NA NA ...
 $ : logi [1:38, 1:2] NA NA NA NA NA NA ...
 $ : logi [1:39, 1:2] NA NA NA NA NA NA ...
 $ : logi [1:40, 1:2] NA NA NA NA NA NA ...

Solution 4

The code below shows how I used Joshua Ulrich's approach to create slightly more complex matrices. Hopefully this answer is helpful is showing some of the flexibility possible in creating objects. If not, I can delete my answer.

I suspect this approach can be modified easily to create matrices that differ in size, for example, by setting nrow or ncol equal to a variable and using rep(q, z) with some variable z to duplicate elements in the vector inside the matrix or rbind statement:

p1.c1 <- 0.10
p2.c1 <- 0.20
p3.c1 <- 0.30
p4.c1 <- 0.40

s1.c1  <- matrix(c(p1.c1, p1.c1, (1 - p1.c1),
                   p1.c1, p1.c1, (1 - p1.c1),
                       0,     0,          1), nrow=3, ncol=3, byrow = TRUE)
s2.c1  <- matrix(c(p2.c1, p2.c1, (1 - p2.c1),
                   p2.c1, p2.c1, (1 - p2.c1),
                       0,     0,          1), nrow=3, ncol=3, byrow = TRUE)
s3.c1  <- matrix(c(p3.c1, p3.c1, (1 - p3.c1),
                   p3.c1, p3.c1, (1 - p3.c1),
                       0,     0,          1), nrow=3, ncol=3, byrow = TRUE)
s4.c1  <- matrix(c(p4.c1, p4.c1, (1 - p4.c1),
                   p4.c1, p4.c1, (1 - p4.c1),
                       0,     0,          1), nrow=3, ncol=3, byrow = TRUE)

n <- 5

p.c1 <- c(p1.c1, p2.c1, p3.c1, p4.c1)

for (i in 1: (n - 1)) {
  assign(paste('xs', i, '.c1', sep=""), matrix(c(p.c1[i], p.c1[i], (1-p.c1[i]),
                                                 p.c1[i], p.c1[i], (1-p.c1[i]),
                                                       0,       0,         1 ), nrow=3, ncol=3, byrow = TRUE))
}
identical(xs1.c1, s1.c1)
identical(xs2.c1, s2.c1)
identical(xs3.c1, s3.c1)
identical(xs4.c1, s4.c1)

for (i in 1: (n - 1)) {
  assign(paste('ys', i, '.c1', sep=""), rbind(c(p.c1[i], p.c1[i], (1-p.c1[i])),
                                              c(p.c1[i], p.c1[i], (1-p.c1[i])),
                                                    c(0,       0,          1)))

}
identical(ys1.c1, s1.c1)
identical(ys2.c1, s2.c1)
identical(ys3.c1, s3.c1)
identical(ys4.c1, s4.c1)
Share:
13,480
Manoel Galdino
Author by

Manoel Galdino

I am a Political Science PHd from University of São Paulo. I work primarily with R as a Data Scientist. I have interest in ohter programing languages, mainly Python, C and SQL.

Updated on June 08, 2022

Comments

  • Manoel Galdino
    Manoel Galdino almost 2 years

    I want to create 27 matrix with 2 columns and a variable number of rows. I could just write 27 lines of code, like this:

     x1 = cbind(rep(1,34), rnorm(34))
    
     x2 = cbind(rep(1,36), rnorm(36))
    

    ....

    x27 = cbind(rep(1,k), rnorm(k))
    

    But it must have a better way to do that. I thought of a loop, something like this:

    aux = c(34, 36, ..., k) # auxiliar variable with number of rows for each matrix
    
    for (i in 1:27) paste("x",i, sep="") =  cbind(rep(1,aux[i]), rnorm(aux[i]))
    

    However, it doesn't work. I feel like this is a simple task, but I am out of ideas.

    Any help?

    ps.: I thought of an array, but I wasn't able to use it. Maybe a list can do the job, I don't know.

  • Manoel Galdino
    Manoel Galdino about 13 years
    But don't you have to create x first? something like x <- list() or x <- vector()? I my computer it didn't found the object x.
  • Manoel Galdino
    Manoel Galdino about 13 years
    Yep, we need to create x first . Thanks very much. I used simply x <- list()
  • daroczig
    daroczig about 13 years
    @Manoel Galdino: yes, sorry for this mistake! I have edited my answer and added the extra line, and also added an example with lapply to make the solution neater in exchange :)
  • Joshua Ulrich
    Joshua Ulrich about 13 years
    Preallocate! Define x <- vector("list",27) before the loop then set each element of x inside the loop. This is much more efficient than expanding the list for each iteration.
  • daroczig
    daroczig about 13 years
    @Joshua Ulrich: true, thank you for pointing out - that is really useful. I have edited my answer to make it nicer. And I have just (after reading your answer) realized that I might had misunderstood the question also :(
  • Joshua Ulrich
    Joshua Ulrich about 13 years
    @daroczig: After saying it was "much" more efficient, I decided to test my claim. It's only marginally more efficient, but it's still good practice. ;-)