32

多数の行と多数の列を持つデータ フレームがあるとします。

列には名前があります。行に番号でアクセスし、列に名前でアクセスします。

たとえば、行をループする 1 つの (おそらく遅い) 方法は次のとおりです。

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

もう 1 つの方法は、個別の列 ( など) の「リスト」を作成column1_list = df[["column1"]し、1 つのループでリストにアクセスすることです。このアプローチは高速かもしれませんが、多くの列にアクセスしたい場合には不便です。

データ フレームの行をループする高速な方法はありますか? 高速ループに適した他のデータ構造はありますか?

4

3 に答える 3

15

コメントを追跡するのが難しく、これについてすでに1つのコメントを失っているため、これを完全な回答にする必要があると思います... forの違いを示すnullglobの例があり、他の例よりもはるかに優れたファミリ関数を適用します. 関数が非常に遅くなるようにすると、すべての速度が消費され、ループのバリエーション間の違いは見られなくなります。しかし、関数を自明にすると、ループがどれだけ物事に影響を与えるかがわかります。

また、他の例では調べられていない apply ファミリーの一部のメンバーには、興味深いパフォーマンス特性があることも付け加えておきます。最初に、私のマシンでの 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 ループはそれほど遅くなりません。

他の投稿でテストされていないように見えるもう 1 つの方法は、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

最速の方法は、ループしないことです(つまり、ベクトル化された操作)。ループする必要がある唯一のインスタンスの1つは、依存関係がある場合です(つまり、ある反復が別の反復に依存している場合)。それ以外の場合は、ループの外側でできるだけ多くのベクトル化された計算を実行してみてください。

ループする必要がある場合、forループの使用は基本的に他の何よりも高速です(lapply少し速くなる可能性がありますが、他のapply関数はとほぼ同じ速度になる傾向がありますfor)。

于 2010-07-26T18:06:54.767 に答える
2

data.frame は基本的に列ベクトルのリストであるという事実を利用して、do.call を使用して、data.frame の各列に列数のアリティを持つ関数を適用できます (リストの「zip」に似ています)。他の言語で)。

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