Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using cbind on an arbitrarily long list of objects

I would like to find a way to create a data.frame by using cbind() to join together many separate objects. For example, if A, B, C & D are all vectors of equal length, one can create data.frame ABCD with

ABCD <- cbind(A,B,C,D)

However, when the number of objects to be combined gets large, it becomes tedious to type out all of their names. Furthermore, Is there a way to call cbind() on a vector of object names, e.g.

objs <- c("A", "B", "C", "D")
ABCD <- cbind(objs)

or on a list containing all the objects to be combined, e.g.

obj.list <- list(A,B,C,D)
ABCD <- cbind(obj.list)

Currently, the only workaround I can think of is to use paste(), cat(), write.table(), and source() to construct the arguments to cbind(), write it as a script and source it. This seems like a very nasty kludge. Also, I have looked into do.call() but can't seem to find a way to accomplish what I want with it.

like image 752
rtyro Avatar asked Apr 04 '11 18:04

rtyro


People also ask

What is the use of Cbind () function?

The cbind function is used to combine vectors, matrices and/or data frames by columns.

What is the difference between Rbind and Cbind?

cbind() and rbind() both create matrices by combining several vectors of the same length. cbind() combines vectors as columns, while rbind() combines them as rows. Let's use these functions to create a matrix with the numbers 1 through 30.

Can you Cbind multiple columns in R?

You can use cbind() function in R to bind multiple columns with ease. It is also a function having a simple syntax as well. You can bind data frames, vectors and multiple columns using this function.


4 Answers

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
like image 136
Prasad Chalasani Avatar answered Oct 19 '22 09:10

Prasad Chalasani


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
like image 27
Aaron left Stack Overflow Avatar answered Oct 19 '22 08:10

Aaron left Stack Overflow


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...

like image 3
aL3xa Avatar answered Oct 19 '22 08:10

aL3xa


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]
like image 1
Wojciech Sobala Avatar answered Oct 19 '22 09:10

Wojciech Sobala