我想找到一种方法来创建一个data.frame,方法是使用cbind()
将许多单独的对象连接在一起。例如,如果A,B,C& D是所有相等长度的向量,可以用
data.frame
ABCD
ABCD <- cbind(A,B,C,D)
但是,当要组合的对象数量变大时,输入所有名称变得冗长乏味。此外,有没有办法在对象名称向量上调用cbind()
,例如
objs <- c("A", "B", "C", "D")
ABCD <- cbind(objs)
或包含所有要组合的对象的列表,例如
obj.list <- list(A,B,C,D)
ABCD <- cbind(obj.list)
目前,我能想到的唯一解决方法是使用paste()
,cat()
,write.table()
和source()
来构建cbind()
的参数,将其写为脚本并将其作为源代码。这似乎是一个非常讨厌的kludge。此外,我已经研究过do.call()
,但似乎无法找到一种方法来实现我想要的东西。
答案 0 :(得分:31)
do.call
函数在这里非常有用:
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
答案 1 :(得分:8)
首先,您需要get
您想要的对象并将它们作为列表存储在一起;如果您可以将其名称构造为字符串,则使用get
函数。在这里,我创建了两个变量A
和B
:
> A <- 1:4
> B <- rep(LETTERS[1:2],2)
然后我使用ns
构造一个包含其名称(存储为get
)和lapply
这些变量的字符向量。然后我将列表的名称设置为与其原始名称相同。
> (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"
然后你可以使用do.call
;第一个参数是你想要的函数,第二个参数是一个包含你要传递给它的参数的列表。
> do.call(cbind, obj.list)
A B
[1,] "1" "A"
[2,] "2" "B"
[3,] "3" "A"
[4,] "4" "B"
然而,正如aL3xa正确指出的那样,这会产生一个矩阵,而不是一个数据帧,如果变量是不同的类,它可能不是你想要的;这里我的A
被强制转换为字符向量而不是数字向量。要从列表中创建数据框,只需在其上调用data.frame
;然后保留变量的类。
> (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
答案 2 :(得分:3)
但是,您应该记住,cbind
仅在原子向量(在这种情况下为double
)上应用时将返回原子向量(矩阵)。正如您在@ prasad和@Aaron的答案中所看到的,结果对象是一个矩阵。如果指定其他原子向量(整数,双精度,逻辑,复数)以及字符向量,它们将被强制转换为字符。然后你有一个问题 - 你必须将它们转换为所需的类。所以,
如果A,B,C&amp; D是所有的向量 等长,人可以创造 data.frame ABCD with
ABCD <- data.frame(A, B, C, D)
也许你应该问“我怎样才能轻松收集相同长度的各种载体并将它们放在data.frame
”中? cbind
很棒,但有时它不是什么你正在寻找......
答案 3 :(得分:1)
您可以使用eapply将环境中的所有向量放入列表中。
obj.list <- eapply(.GlobalEnv,function(x) if(is.vector(x)) x)
obj.list <- obj.list[names(obj.list) %in% LETTERS]