2

サイズ365x7x4の3次元マトリックスを設定しました。

x <- array(rep(1, 365*5*4), dim=c(365, 5, 4))

次に、forループを使用して、各要素に値を入力します。各要素の値は、行、列、および深さの合計である必要があるとしましょう。これは比較的簡単だと思います。

ありがとう!最高、F

4

2 に答える 2

7

より簡単な例を使用して、何が行われているのかを確認できます

arr <- array(seq_len(3*3*3), dim = rep(3,3,3))

次のコードは、要求された出力を提供します。

dims <- dim(arr)
ind <- expand.grid(lapply(dims, seq_len))
arr[] <- rowSums(ind)

上記は与える

> arr
, , 1

     [,1] [,2] [,3]
[1,]    3    4    5
[2,]    4    5    6
[3,]    5    6    7

, , 2

     [,1] [,2] [,3]
[1,]    4    5    6
[2,]    5    6    7
[3,]    6    7    8

, , 3

     [,1] [,2] [,3]
[1,]    5    6    7
[2,]    6    7    8
[3,]    7    8    9

> arr[1,1,1]
[1] 3
> arr[1,2,3]
[1] 6
> arr[3,3,3]
[1] 9

更新:ここで@TimPの回答の例を使用して、回答を更新し、よりRに似た方法で実行する方法を示します。

与えられた

arr <- array(seq_len(3*3*3), dim = rep(3,3,3))

の要素arri + j + kunlessk > 2に置き換えます。ただし、その場合j*k-iは代わりに使用されます。

dims <- dim(arr)
ind <- expand.grid(lapply(dims, seq_len))
## which k > 2
want <- ind[,3] > 2
arr[!want] <- rowSums(ind[!want, ])
arr[want] <- ind[want, 2] * ind[want, 3] - ind[want, 1]

ループのようなおなじみのイディオムに固執することは魅力的であり、一般的な信念に反して、ループはRで非効率的ではありませんが、ベクトル化された方法で考えることを学ぶことは、言語を学び、それをデータ分析タスクに適用し始めるときに何倍も報われるでしょう。

ファビアンの例のいくつかのタイミングは次のとおりです。

> x <- array(rep(1, 365*5*4), dim=c(365, 5, 4))
> system.time({
+ for (i in seq_len(dim(x)[1])) {
+     for (j in seq_len(dim(x)[2])) {
+         for (k in seq_len(dim(x)[3])) {
+             val = i+j+k
+             if (k > 2) {
+                 val = j*k-i
+             }
+             x[i,j,k] = val
+         }
+     }
+ }
+ })
   user  system elapsed 
  0.043   0.000   0.044 
> arr <- array(rep(1, 365*5*4), dim=c(365, 5, 4))
> system.time({
+ dims <- dim(arr)
+ ind <- expand.grid(lapply(dims, seq_len))
+ ## which k > 2
+ want <- ind[,3] > 2
+ arr[!want] <- rowSums(ind[!want, ])
+ arr[want] <- ind[want, 2] * ind[want, 3] - ind[want, 1]
+ })
   user  system elapsed 
  0.005   0.000   0.006

そして、はるかに大きな(少なくとも私の厄介なラップトップにとっては!)問題の場合

> x <- array(rep(1, 200*200*200), dim=c(200, 200, 200))
> system.time({
+ for (i in seq_len(dim(x)[1])) {
+     for (j in seq_len(dim(x)[2])) {
+         for (k in seq_len(dim(x)[3])) {
+             val = i+j+k
+             if (k > 2) {
+                 val = j*k-i
+             }
+             x[i,j,k] = val
+         }
+     }
+ }
+ })
   user  system elapsed 
 51.759   0.129  53.090
> arr <- array(rep(1, 200*200*200), dim=c(200, 200, 200))
> system.time({
+     dims <- dim(arr)
+     ind <- expand.grid(lapply(dims, seq_len))
+     ## which k > 2
+     want <- ind[,3] > 2
+     arr[!want] <- rowSums(ind[!want, ])
+     arr[want] <- ind[want, 2] * ind[want, 3] - ind[want, 1]
+ })
   user  system elapsed 
  2.282   1.036   3.397 

しかし、それでも今日の基準では控えめから小さいかもしれません。そのメソッドに必要なすべての関数呼び出しのために、ループがこれまで以上に競争力を失い始めていることがわかります。

于 2012-06-10T10:20:03.423 に答える
3

ファビアン:あなたの質問の言い回しから、あなたはあなたが考案するかもしれないルールのセットに従うために配列に値を設定する簡単な方法を探しているだけだと思います。問題ない。

あなたの配列は小さいです(そして文脈から、あなたはそのサイズの何かのためにコードを使いたいだけだと強く思います)。したがって、3つのループのセットを使用することをお勧めしforます。これは、ほぼ瞬時に実行されます。不要な複雑さは必要ありません。以下の私のコードは例を示しています。ここでは、要素x[i,j,k]をに設定しますi+j+k。ただしk>2、の場合は、代わりにに設定しますj*k-i

もちろん、必要な数のルールを設定できます。if各ルールにステートメントを追加し、その条件が真の場合に取得するval値として定義するだけです。x[i,j,k](これを設定する方法はいくつかありますが、これは最も理解しやすいようです。)最も内側のループの最後で、x[i,j,k]必要な値(val)に設定され、次の要素が完了するまで実行されます。 'すべて完了しました。それでおしまい!

x = array(rep(1, 365*5*4), dim=c(365, 5, 4))

for (i in seq_len(dim(x)[1])) {
    for (j in seq_len(dim(x)[2])) {
        for (k in seq_len(dim(x)[3])) {
            val = i+j+k
            if (k > 2) {
                val = j*k-i
            }
            x[i,j,k] = val
        }
    }
}

お役に立てれば :)

クイックアップデート(ループのない方法):完全を期すために、本当に急いでいて、コードを0.19秒ではなく0.07秒で実行したい場合は、次のようにベクトル的に設定することもできます。

comb = expand.grid(seq_len(365), seq_len(5), seq_len(4))
i = comb$Var1; j = comb$Var2; k = comb$Var3
val = i+j+k
subs = which(k>2); val[subs] = (j*k-i)[subs]
x = array(val, dim = c(365, 5, 4))

上記では、変数ijおよびkは長さ7300(配列内のセルの数)のベクトルです。前と同じように、のデフォルトの選択はサブセットを除いてval合計です。代わりに、は-私の答えの最初の部分の例とまったく同じです。明らかに、このメソッドの表記はかなり難しいので、ループベースのソリューションを紹介する方がよいと思いました。うまくいけば、上記に他の条件を追加する方法がわかるでしょう。最後の行は、それぞれが正しい値をとるように、ベクトルを正しい方法で配列にマップします。それを試してみてください:)i+j+kk>2valj*k-ivalxx[i,j,k]val

ただし、注意すべき小さな点が1つあります。この種のアルゴリズムを大規模な配列(現在のアルゴリズムよりもはるかに大きい)で実行したい場合は、すぐ上のアプローチを使用することをお勧めします。実行時間を最小限に抑えるため。あなたの場合、ランタイムは実際には問題ではないので、私のアドバイスは、あなたがより快適に感じるものを使用することです。

乾杯!:)

于 2012-06-10T18:41:07.637 に答える