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.
The cbind function is used to combine vectors, matrices and/or data frames by columns.
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.
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.
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]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With