2

R x C 行列が k 番目の行まで入力され、この行の下は空になっています。私がする必要があるのは、残りの行を埋めることです。これを行うために、2行全体を引数として取り、これらの行を処理し、2つの新しい行を出力する関数があります(これらの出力は、行列の空の行を2つのバッチで埋めます)。処理する行のすべての「ペア」を含む固定マトリックスがありますが、for ループがパフォーマンスに役立っていません。

# the processRows function:
processRows = function(r1, r2)
{
  # just change a little bit the two rows and return it in a compact way    
  nr1 = r1 * 0.1
  nr2 = -r2 * 0.1

  matrix (c(nr1, nr2), ncol = 2)
 }

# M is the matrix
# nrow(M) and k are even, so nLeft is even

M = matrix(1:48, ncol = 3)
# half to fill (can be more or less, but k is always even)
k = nrow(M)/2

# simulate empty rows to be filled
M[-(1:k), ] = 0

cat('before fill')
print(M)

# number of empty rows to fill
nLeft  = nrow(M) - k
nextRow = k + 1

# each row in idxList represents a 'pair' of rows to be processed 
# any pairwise combination of non-empty rows could happen
# make it reproducible

set.seed(1)
idxList = matrix (sample(1:k, k), ncol = 2, byrow = TRUE)

for ( i in 1 : (nLeft / 2))
{
   row1 = M[idxList[i, 1],]
   row2 = M[idxList[i, 2],]

   # the two columns in 'results' will become 2 rows in M
   results = processRows(row1, row2)

   # fill the matrix
   M[nextRow, ] = results[, 1]
   nextRow = nextRow + 1
   M[nextRow, ] = results[, 2]
   nextRow = nextRow + 1
 }

 cat('after fill')
 print(M)
4

1 に答える 1

3

さて、これが最初のコードです。これを実行して、再現したい「真の」マトリックスのコピーをより速く作成します。

#### Original Code (aka Gold Standard) ####
M = matrix(1:48, ncol = 3)
k = nrow(M)/2
M[-(1:k), ] = 0
nLeft  = nrow(M) - k
nextRow = k + 1
idxList = matrix(1:k, ncol = 2)
for ( i in 1 : (nLeft / 2))
{
    row1 = M[idxList[i, 1],]
    row2 = M[idxList[i, 2],]
    results = matrix(c(2*row1, 3*row2), ncol = 2)
    M[nextRow, ] = results[, 1]
    nextRow = nextRow + 1
    M[nextRow, ] = results[, 2]
    nextRow = nextRow + 1
}

これがベクトル化されたコードです。基本的な考え方は、処理している行が4つある場合です。それらを一度に1つずつベクトルとして渡すのではなく、一度に渡します。あれは:

(1:3) * 2
(1:3) * 2
(1:3) * 2
(1:3) * 2

と同じです(ただし遅い):

c(1:3, 1:3, 1:3, 1:3) * 2

したがって、最初に同じセットアップコードを使用し、次に2つの長いベクトルとして処理される行を作成します(上記の簡単な例のように、4つの元の行すべてがつなぎ合わされています)。次に、それらの結果を取得し、適切な次元の行列に変換します。最後の秘訣は、たった2つのステップで結果を割り当てることです。行列の複数の行に一度に割り当てることができるので、seq()奇数と偶数を取得するために使用するので、結果の最初の列と2番目の列をそれぞれに割り当てます。

#### Vectorized Code (testing) ####
M2 = matrix(1:48, ncol = 3)
k2 = nrow(M2)/2
M2[-(1:k2), ] = 0
nLeft2  = nrow(M2) - k2
nextRow2 = k2 + 1
idxList2 = matrix(1:k2, ncol = 2)

## create two long vectors of all rows to be processed
row12 <- as.vector(t(M2[idxList2[, 1],]))
row22 <- as.vector(t(M2[idxList2[, 2],]))

## get all results
results2 = matrix(c(2*row12, 3*row22), ncol = 2)

## add results back
M2[seq(nextRow2, nextRow2 + nLeft2-1, by = 2), ] <- matrix(results2[,1], nLeft2/2, byrow=TRUE)
M2[seq(nextRow2+1, nextRow2 + nLeft2, by = 2), ] <- matrix(results2[,2], nLeft2/2, byrow=TRUE)

## check that vectorized code matches your examples
all.equal(M, M2)

私のマシンではどれが得られますか:

> all.equal(M, M2)
[1] TRUE
于 2012-07-09T04:29:28.860 に答える