2016-02-06 2 views
5

ループの改善が以前に何回も求められています。 Rのforループを改善するためにファミリ関数を適用することができます。別の行列に応じて行列操作のループを改善する方法

しかし、これらの操作が別の行列に依存する行列の操作を改善する方法はありますか?

for (i in 1:nrow(test)){ 
    test[i,index[i,]] <- 2 
} # where index is predetermined matrix 

もう一つの例は、私は内の要素の順序に基づいてtestに値を設定するところ、この、次のとおりです。私はここに意味することは、私がtestに2に設定要素が別の行列indexに基づいてされている場合、これは、あります別の行列anyMatrixの行:

for (i in 1:nrow(test)){ 
    test[i,] <- order(anyMatrix[i,]) 
} 

私はここにlapplyまたはsapply使用することができますが、それらはリストを返し、それが行列に戻ってそれを変換するために同じ時間がかかります。

再現例:

test <- matrix(0, nrow = 10, ncol = 10) 
set.seed(1234) 
index <- matrix(sample.int(10, 10*10, TRUE), 10, 10) 
anyMatrix <- matrix(rnorm(10*10), nrow = 10, ncol = 10) 

for (i in 1:nrow(test)){ 
    test[i,index[i,]] <- 2 
} 

for (i in 1:nrow(test)){ 
    test[i,] <- order(anyMatrix[i,]) 
} 

答えて

6

あなたが本当にここに二つの別々の問題を抱えているように見えます。

問題1:行列index考えると、それぞれの行と列ijのためにあなたがjindexの行iに表示された場合は2にtest[i,j]を設定します。これは単純な行列インデックスを使って行うことができます。インデックスの2列の行列を渡します。最初の列はインデックスを作成するすべての要素の行で、2列目はインデックスを作成するすべての要素の列です。

test[cbind(as.vector(row(index)), as.vector(index))] <- 2 
test 
#  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] 
# [1,] 2 2 0 2 2 2 2 0 2  2 
# [2,] 2 0 2 2 2 2 2 0 2  2 
# [3,] 2 2 2 2 0 0 2 2 0  0 
# [4,] 2 2 0 0 0 2 2 2 0  2 
# [5,] 2 2 2 2 0 0 0 0 2  0 
# [6,] 0 0 0 0 0 2 2 2 2  0 
# [7,] 2 0 2 2 2 2 2 0 0  0 
# [8,] 2 0 2 2 2 2 0 2 0  2 
# [9,] 2 2 2 2 0 0 2 0 2  2 
# [10,] 2 0 2 0 0 2 2 2 2  0 

これはすべての操作を1回のベクトル化操作で実行するので、行をループして個別に処理するよりも高速に処理する必要があります。ここでは、100万行と10列の例を示します。

OP <- function(test, index) { 
    for (i in 1:nrow(test)){ 
    test[i,index[i,]] <- 2 
    } 
    test 
} 
josliber <- function(test, index) { 
    test[cbind(as.vector(row(index)), as.vector(index))] <- 2 
    test 
} 
test.big <- matrix(0, nrow = 1000000, ncol = 10) 
set.seed(1234) 
index.big <- matrix(sample.int(10, 1000000*10, TRUE), 1000000, 10) 
identical(OP(test.big, index.big), josliber(test.big, index.big)) 
# [1] TRUE 
system.time(OP(test.big, index.big)) 
# user system elapsed 
# 1.564 0.014 1.591 
system.time(josliber(test.big, index.big)) 
# user system elapsed 
# 0.408 0.034 0.444 

ここで、ベクトル化アプローチは3.5倍高速です。

問題2:あなたはordertestの行iを設定したいanyMatrixの対応する行に適用されます。あなたはapplyでこれを行うことができます。

(test <- t(apply(anyMatrix, 1, order))) 
#  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] 
# [1,] 1 10 7 8 4 5 3 6 2  9 
# [2,] 8 7 1 6 3 4 9 5 10  2 
# [3,] 4 9 7 1 3 2 6 10 5  8 
# [4,] 1 2 6 4 10 3 9 8 7  5 
# [5,] 9 6 5 1 2 7 10 4 8  3 
# [6,] 9 3 8 6 5 10 1 4 7  2 
# [7,] 3 7 2 5 6 8 9 4 1 10 
# [8,] 9 8 1 3 4 6 7 10 5  2 
# [9,] 8 4 3 6 10 7 9 5 2  1 
# [10,] 4 1 9 3 6 7 8 2 10  5 

applyが本当にちょうどあなたがあなたの溶液中でループしたかと同様に行をループしているので、私は、ここで実行時の変化の多くを期待していません。それでも、私はこのソリューションを好むでしょう。なぜなら、それはタイピングが少なく、 "R"なやり方だからです。

これらのアプリケーションではかなり異なるコードが使用されていますが、Rデータ操作ではかなり典型的です。さまざまな特殊な演算子があり、タスクに適したコードを選択する必要があります。私は、その操作が別の行列からのデータに基づいているすべての行列操作を扱うことができる単一の関数または実際には小さな関数のセットがあるとは思わない。

+0

ありがとうございますが、最初のものではどのようにcbindが高速になりますか? cbindは通常のforループよりも時間がかかりませんか?ベンチマークはありますか? – rmania

+0

@rmania私はこの回答を更新し、ベクトル化された索引操作がループの代替案と比較してスピードアップをもたらすことを示すベンチマークを追加しました。 Rでは、多くの繰り返し高速処理を1つの処理に置き換えると、それらをすべて一緒に実行すると、大量の高速化が行われることがあります。 – josliber

関連する問題