que - merge rows in r
Usando cbind en una lista arbitrariamente larga de objetos (4)
La función do.call
es muy útil aquí:
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
Me gustaría encontrar una forma de crear un data.frame usando cbind()
para unir muchos objetos separados. Por ejemplo, si A, B, C y D son todos vectores de igual longitud, uno puede crear data.frame
ABCD con
ABCD <- cbind(A,B,C,D)
Sin embargo, cuando la cantidad de objetos que se combinarán aumenta, es tedioso escribir todos sus nombres. Además, ¿hay alguna manera de llamar a cbind()
en un vector de nombres de objetos, por ejemplo,
objs <- c("A", "B", "C", "D")
ABCD <- cbind(objs)
o en una lista que contiene todos los objetos a combinar, por ejemplo
obj.list <- list(A,B,C,D)
ABCD <- cbind(obj.list)
Actualmente, la única solución que puedo pensar es usar paste()
, cat()
, write.table()
y source()
para construir los argumentos a cbind()
, escribirlos como un script y cbind()
. Esto parece un desafío muy desagradable. Además, he do.call()
pero parece que no puedo encontrar la manera de lograr lo que quiero con él.
Primero necesita get
los objetos que desea y almacenarlos juntos como una lista; si puedes construir sus nombres como cadenas, usas la función get
. Aquí creo dos variables, A
y B
:
> A <- 1:4
> B <- rep(LETTERS[1:2],2)
Luego construyo un vector de caracteres que contiene sus nombres (almacenados como ns
) y get
estas variables usando lapply
. Luego configuré los nombres de la lista para que sean los mismos que sus nombres originales.
> (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"
Entonces puedes usar do.call
; el primer argumento es la función que desea y el segundo es una lista con los argumentos que desea pasarle.
> do.call(cbind, obj.list)
A B
[1,] "1" "A"
[2,] "2" "B"
[3,] "3" "A"
[4,] "4" "B"
Sin embargo, como aL3xa notas correctamente, esto hace una matriz, no un marco de datos, que puede no ser lo que quieres si las variables son clases diferentes; aquí mi A
ha sido forzada a un vector de caracteres en lugar de un vector numérico. Para hacer un marco de datos de una lista, simplemente llama a data.frame
; entonces las clases de las variables se conservan.
> (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
Puede poner todos los vectores en el entorno en lista usando eapply.
obj.list <- eapply(.GlobalEnv,function(x) if(is.vector(x)) x)
obj.list <- obj.list[names(obj.list) %in% LETTERS]
Sin embargo, debes tener en cuenta que cbind
devolverá un vector atómico (matriz) cuando se aplica únicamente a vectores atómicos (el double
en este caso). Como puede ver en las respuestas de @prasad y @ Aaron, el objeto resultante es una matriz. Si especifica otros vectores atómicos (entero, doble, lógico, complejo) junto con el vector de caracteres, se verán obligados a usar el carácter. Y luego tienes un problema: tienes que convertirlos a las clases deseadas. Asi que,
si A, B, C y D son vectores de la misma longitud, se puede crear un archivo ABCD con data.frame
ABCD <- data.frame(A, B, C, D)
Quizás debería preguntar "¿cómo puedo reunir fácilmente varios vectores de igual longitud y ponerlos en un data.frame
"? cbind
es genial, pero a veces no es lo que estás buscando ...