1
bucketIndex <- function(v, N){
  o <- rep(0, length(v))

  curSum <- 0
  index  <- 1

  for(i in seq(length(v))){
    o[i] <- index

    curSum <- curSum + v[i]
    if(curSum > N){
      curSum <- 0
      index <- index + 1
    }
  }

  o
}

> bucketIndex(c(1, 1, 2, 1, 5, 1), 3)
[1] 1 1 1 2 2 3

この関数は基本的にベクトル化できないのではないかと思います。もしそうなら、この「クラス」の関数を処理するためのパッケージはありますか、それともAC拡張としてそれを書くための唯一の代替手段(速度が必要な場合)ですか?

4

3 に答える 3

2

ここで試してみましょう(まだ到達していませんbucketIndex!):

  • 君の

    curSum <- curSum + v[i]
    if(curSum > N){
      curSum <- 0
      index <- index + 1
    }  
    

    のほぼ整数除算%/%ですcumsum (v)

  • しかし、完全ではありません。v [i] が > 数回Nで、1 から始めても、インデックスは 1 しかカウントアップしません。これは、因数に変換してから整数に戻すことでほとんど処理できます。

  • ただし、(関数の名前から) この動作が本当に意図されているかどうかは疑問です。

    > bucketIndex (c(1, 1, 2, 1, 2, 1, 1, 2, 1, 5, 1), 3)
    [1] 1 1 1 2 2 2 3 3 3 4 5
    > bucketIndex (c(1, 1, 1, 2, 2, 1, 1, 2, 1, 5, 1), 3)
    [1] 1 1 1 1 2 2 2 3 3 3 4
    

    つまり、 2 つの連続するエントリを交換するだけvで、結果の最大値が異なる可能性があります。

  • もう 1 つのポイントは、合計が > になる要素のでのみカウントアップすることですN。これは、結果の先頭に 1 を追加し、最後の要素を削除する必要があることを意味します。

  • curSumどれだけ撃っても0にリセットされNます。したがって、 を持つすべての要素についてcumsum (v) > N、この値を減算してから、次のものを探す必要がありますcumsum (v) > N。これにより、ループに対するループの反復回数が減少しますforが、これにより実質的な改善が得られるかどうかは、vおよびのエントリN(またはmax (index):length (v)比率) によって異なります。それがあなたの例のように 50% である場合、実質的な利益は得られないと思います。それらの間に少なくとも1桁の大きさがない限り、私はinline::cfunction.

于 2012-10-05T16:56:41.043 に答える
0

私はここで手足を出して、答えは「いいえ」だと言います。基本的に、現在の合計の結果に基づいて合計するものを変更しています。これは、将来の計算がベクトル化された操作では実行できない中間計算の結果に依存することを意味します。

于 2012-10-05T17:37:53.603 に答える
0

これが完全にベクトル化できるとは思いませんが、@cbeleites は、一度にチャンク (バケット) 全体を処理することにより、ループ内の反復回数を減らす 1 つの方法を取得します。各反復は、累積合計が を超える場所を探し、Nその範囲にインデックスを割り当て、超過した値によって累積合計を減らし、Nベクトルが使い果たされるまで繰り返します。残りは簿記(値の初期化と値の増分)です。

bucketIndex2 <- function(v, N) {
    index <- 1
    cs <- cumsum(v)
    bk.old <- 0
    o <- rep(0, length(v))

    repeat {
        bk <- suppressWarnings(min(which(cs > N)))
        o[(bk.old+1):min(bk,length(v))] <- index
        if (bk >= length(v)) break
        cs <- cs - cs[bk]
        index <- index + 1
        bk.old <- bk
    }

    o
}

これは、さまざまなランダム入力の関数と一致します。

for (i in 1:200) {
  v <- sample(sample(20,1), sample(50,1)+20, replace=TRUE)
  N <- sample(10,1)
  bi <- bucketIndex(v, N)
  bi2 <- bucketIndex2(v, N)
  if (any(bi != bi2)) {
    print("MISMATCH:")
    dump("v","")
    dump("N","")
  }
}
于 2012-10-05T17:38:49.797 に答える