32

假设您有一个包含多行多列的数据框。

列有名称。您想按数字访问行,按名称访问列。

例如,一种(可能很慢)循环遍历行的方法是

for (i in 1:nrow(df)) {
  print(df[i, "column1"])
  # do more things with the data frame...
}

另一种方法是为单独的列(如column1_list = df[["column1"])创建“列表”,并在一个循环中访问列表。这种方法可能很快,但如果您想访问许多列,也很不方便。

是否有一种快速循环数据框行的方法?其他一些数据结构是否更适合快速循环?

4

3 回答 3

15

我认为我需要将其作为一个完整的答案,因为我发现评论更难追踪,而且我已经失去了对此的评论...... nullglob的一个例子展示了 for 之间的差异,并且比其他例子更好地应用家庭函数. 当一个函数使得它非常慢时,这就是所有速度都被消耗的地方,你不会发现循环变化之间的差异。但是,当您使函数变得微不足道时,您可以看到循环对事物的影响有多大。

我还想补充一点,在其他示例中未探索的应用系列的一些成员具有有趣的性能属性。首先,我将在我的机器上显示 nullglob 的相关结果的复制。

n <- 1e6
system.time(for(i in 1:n) sinI[i] <- sin(i))
  user  system elapsed 
 5.721   0.028   5.712 

lapply runs much faster for the same result
system.time(sinI <- lapply(1:n,sin))
   user  system elapsed 
  1.353   0.012   1.361 

他还发现 sapply 慢得多。这是其他一些未经测试的。

普通旧适用于数据的矩阵版本......

mat <- matrix(1:n,ncol =1),1,sin)
system.time(sinI <- apply(mat,1,sin))
   user  system elapsed 
  8.478   0.116   8.531 

因此,apply() 命令本身比 for 循环慢很多。(如果我使用 sin(mat[i,1]),for 循环不会明显减慢。

另一个似乎没有在其他帖子中测试过的另一个是 tapply。

system.time(sinI <- tapply(1:n, 1:n, sin))
   user  system elapsed 
 12.908   0.266  13.589 

当然,人们永远不会以这种方式使用 tapply,而且在大多数情况下,它的实用性远远超出了任何此类速度问题。

于 2010-07-26T22:14:07.240 回答
12

最快的方法是不循环(即矢量化操作)。您需要循环的唯一实例之一是存在依赖关系(即一个迭代依赖于另一个迭代)。否则,请尝试在循环外尽可能多地进行矢量化计算。

如果您确实需要循环,那么使用for循环基本上和其他任何东西一样快(lapply可以快一点,但其他apply功能往往与速度相同for)。

于 2010-07-26T18:06:54.767 回答
2

利用 data.frames 本质上是列向量列表这一事实,可以使用 do.call 应用一个函数,该函数具有 data.frame 的每一列上的列数(类似于列表上的“压缩”)其他语言)。

do.call(paste, data.frame(x=c(1,2), z=c("a","b"), z=c(5,6)))
于 2015-11-30T17:50:49.370 回答