Using cbind on an arbitrarily long list of objects

风流意气都作罢 提交于 2019-11-27 08:50:21

The do.call function is very useful here:

A <- 1:10
B <- 11:20
C <- 20:11

> do.call(cbind, list(A,B,C))
      [,1] [,2] [,3]
 [1,]    1   11   20
 [2,]    2   12   19
 [3,]    3   13   18
 [4,]    4   14   17
 [5,]    5   15   16
 [6,]    6   16   15
 [7,]    7   17   14
 [8,]    8   18   13
 [9,]    9   19   12
[10,]   10   20   11

First you need to get the objects you want and store them together as a list; if you can construct their names as strings, you use the get function. Here I create two variables, A and B:

> A <- 1:4
> B <- rep(LETTERS[1:2],2)

I then construct a character vector containing their names (stored as ns) and get these variables using lapply. I then set the names of the list to be the same as their original names.

> (ns <- LETTERS[1:2])
[1] "A" "B"
> obj.list <- lapply(ns, get)
> names(obj.list) <- ns
> obj.list
$A
[1] 1 2 3 4

$B
[1] "A" "B" "A" "B"

Then you can use do.call; the first argument is the function you want and the second is a list with the arguments you want to pass to it.

> do.call(cbind, obj.list)
     A   B  
[1,] "1" "A"
[2,] "2" "B"
[3,] "3" "A"
[4,] "4" "B"

However, as aL3xa correctly notes, this makes a matrix, not a data frame, which may not be what you want if the variables are different classes; here my A has been coerced to a character vector instead of a numeric vector. To make a data frame from a list, you just call data.frame on it; then the classes of the variables are retained.

> (AB <- data.frame(obj.list))
  A B
1 1 A
2 2 B
3 3 A
4 4 B
> sapply(AB, class)
        A         B 
"integer"  "factor" 
> str(AB)
'data.frame':   4 obs. of  2 variables:
 $ A: int  1 2 3 4
 $ B: Factor w/ 2 levels "A","B": 1 2 1 2

You should bare in mind, though, that cbind will return an atomic vector (matrix) when applied solely on atomic vectors (double in this case). As you can see in @prasad's and @Aaron's answers, resulting object is a matrix. If you specify other atomic vectors (integer, double, logical, complex) along with character vector, they will get coerced to character. And then you have a problem - you have to convert them to desired classes. So,

if A, B, C & D are all vectors of equal length, one can create data.frame ABCD with

ABCD <- data.frame(A, B, C, D)

Perhaps you should ask "how can I easily gather various vectors of equal length and put them in a data.frame"? cbind is great, but sometimes it's not what you're looking for...

You can put all vectors in environment into list using eapply.

obj.list <- eapply(.GlobalEnv,function(x) if(is.vector(x)) x)
obj.list <- obj.list[names(obj.list) %in% LETTERS]
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!