逐行创建R数据帧

问题描述 投票:103回答:8

我想在R中逐行构造一个数据帧。我做了一些搜索,然后想到的是创建一个空列表,保持列表索引标量,然后每次添加到该列表是一个单行数据帧,并将列表索引前移一个。最后,在列表上为do.call(rbind,)

虽然这有效,但似乎很麻烦。没有简单的方法可以实现相同的目标吗?

显然,我指的是我无法使用某些apply函数,并且明确需要逐行创建数据帧的情况。至少,有一种方法可以使push进入列表的末尾,而不是明确跟踪最后使用的索引吗?

list r dataframe
8个回答
91
投票
这并不意味着您应该。动态增长的结构是用R进行编码的效率最低的方法之一。

如果可以,请预先分配整个data.frame:

N <- 1e4 # total number of rows to preallocate--possibly an overestimate DF <- data.frame(num=rep(NA, N), txt=rep("", N), # as many cols as you need stringsAsFactors=FALSE) # you don't know levels yet

然后在操作过程中一次插入行

DF[i, ] <- list(1.4, "foo")

这应该适用于任意data.frame并且效率更高。如果您超过N,则总是可以在末尾缩小空白行。


47
投票
df<-NULL; while(...){ #Some code that generates new row rbind(df,row)->df }

例如

df<-NULL
for(e in 1:10) rbind(df,data.frame(x=e,square=e^2,even=factor(e%%2==0)))->df
print(df)

9
投票
> DF <- do.call(rbind,Map(function(x) data.frame(a=x,b=x+1),x=1:3)) > DF x y 1 1 2 2 2 3 3 3 4 > class(DF) [1] "data.frame"

我经常使用这种结构。


8
投票
从哲学上讲,您在功能范式方面处于一种罪恶状态,该范式试图确保每个值

出现独立于其他所有值;更改一个值永远不会导致另一个值的可见更改,就像您在C语言中共享指针的方式一样。

[当函数式编程向小型飞船发出信号,而小型飞船回答“我是灯塔”时,就会出现问题。同时,对要处理的大对象进行一系列小改动,可以使您进入灯塔领域。

在C ++ STL中,push_back()是一种生活方式。它并没有试图发挥功能,但是确实试图适应常见的编程习惯

有效地

[在幕后有些聪明,您有时可以安排在每个世界中一只脚走路。基于快照的文件系统就是一个很好的例子(它是从联合安装等概念发展而来的,该概念也同时包含了双方)。

如果R Core想要这样做,则底层向量存储可以像联合安装那样工作。对向量存储的一种引用可能对下标1:N有效,而对相同存储的另一种引用对下标1:(N+1)有效。可能存在尚未方便快速引用push_back()的任何东西有效引用的保留存储。在任何现有参考认为有效的范围之外进行附加时,都不会违反功能概念。

最终最终以增量方式追加行,将耗尽保留的存储空间。您需要创建所有内容的新副本,并将存储空间乘以一定的增量。我使用的STL实现在扩展分配时倾向于将存储量乘以2。我以为我在R Internals中读到了一种内存结构,其中存储量增加了20%。无论哪种方式,生长操作都相对于附加元素总数以对数频率进行。按摊销基准,这通常是可以接受的。

随着幕后花招的流传,我看到的更糟。每次将新行push_back()插入数据帧时,都需要复制一个顶层索引结构。新行可以追加到共享表示中,而不会影响任何旧功能值。我什至不认为这会使垃圾收集器复杂化。因为我不建议push_front(),所以所有引用都是已分配向量存储区前面的前缀引用。


1
投票

1
投票

0
投票

0
投票
© www.soinside.com 2019 - 2024. All rights reserved.