2017-08-02 13 views
3

私は効率的にRのベクトルの逸脱(逆に特定の順列)を作成する方法を検討しています 私が見た限り、基本機能はありませんそれはあまりにもここにはあまりないです。効率的にベクトルの逸脱を作成するR

明らかな始まりは、ベクトルの順列を作成するsampleです。しかし、私は固定点を持たないためにこの順列が必要なので、ベクトルの混乱になります。このトピックの説明は、this Cross Validated postを参照してください。

これが私の最初のアプローチです:ベクトルxxpと呼ばれるxの与えられた順列との間には一定のポイントがあるかどう

derangr <- function(x){ 

    while(TRUE){ 

    xp <- sample(x) 

    if(sum(xp == x) == 0) break 

    } 

    return(xp) 

} 

のでwhileループ内で、私はチェックしています。存在しない場合は、ループを解除してベクターを返します。

結果が示すように、それが正常に動作します:

> derangr(1:10) 
[1] 4 5 6 10 7 2 1 9 3 8 

> derangr(LETTERS) 
[1] "C" "O" "L" "J" "A" "I" "Y" "M" "G" "T" "S" "R" "Z" "V" "N" "K" "D" "Q" "B" "H" "F" "E" "X" "W" "U" "P" 

それを行うのは良い方法がありますのであれば、私は潜在的にいくつかの種類のベクトル化によってwhileを代入すると、思ったんだけど。私はまた、スケーラビリティに注目したいと思っています。ここで

は、両方の例については microbenchmarkです:

library(microbenchmark) 

> microbenchmark(derangr(1:10),times = 10000) 
Unit: microseconds 
      expr min  lq mean median  uq  max neval 
derangr(1:10) 8.359 15.492 40.1807 28.3195 49.4435 6866.453 10000 

> microbenchmark(derangr(LETTERS),times = 10000) 
Unit: microseconds 
      expr min  lq  mean median  uq  max neval 
derangr(LETTERS) 24.385 31.123 34.75819 32.4475 34.3225 10200.17 10000 

同じ質問が定点nの与えられた数の順列を生成する、逆に適用されます。

arrangr <- function(x,n){ 

    while(TRUE){ 

    xp <- sample(x) 

    if(sum(xp == x) == n) break 
    } 

    return(xp) 

} 
+2

'rep(LETTERS、2)'のようにいくつかの値がベクトル内に複数存在しますか?もしそうなら、最初の "A"が2番目の "A"などと交換されるかどうかは重要ですか? – loki

+0

私は一般的な解決策を探しているので、良い点を挙げています。私の関数は一意の値を仮定します。もしあなたが繰り返し値を持っていれば、前の位置に要素(または逆に 'n')要素が残っていない限り、拳" A "が2番目の要素によって交換されるかどうかは関係ありません。 – Val

答えて

1

あなたが持っていない場合一意の値のみを使用すると、インデックスを再配置して新しい順序で入力ベクトルをサブセット化するために使用できます。この場合、たとえばrep(LETTERS, 2)の場合、最初のAと2番目のAは交換可能です。 Qで提案されているderangr()関数もこれらを再配置します。

derangr2 <- function(x){ 
    ind <- seq_along(x) 
    while(TRUE){ 
    indp <- sample(ind) 
    if(sum(indp == ind) == 0) break 

    } 
    return(x[indp]) 
} 

いくつかのベンチマーク結果:

microbenchmark(derangr(rep(LETTERS, 4)), 
       derangr2(rep(LETTERS, 4)), times = 1000) 

# Unit: microseconds 
#      expr min  lq  mean median  uq  max neval 
# derangr(rep(LETTERS, 4)) 6.258 113.4895 441.831094 251.724 549.384 5837.143 1000 
# derangr2(rep(LETTERS, 4)) 6.542 7.3960 23.173800 12.800 22.755 4645.936 1000 

あなただけのユニークな値に直面している場合は、このアプローチは、改善の多くを保持していません。

microbenchmark(derangr(1:1000), derangr2(1:1000), times = 1000) 
# Unit: microseconds 
#    expr min  lq  mean median  uq  max neval 
# derangr(1:1000) 19.341 21.333 61.55154 40.959 78.0775 2770.382 1000 
# derangr2(1:1000) 23.608 25.884 72.76647 46.079 84.1930 2674.243 1000 
+1

+1あなたのコメントを読んだら、私は似たような考えを持っていました。これは間違いなく改善です。私の質問の一部に戻って、whileや他のループを代用する方法はありませんか?もしそうなら、私はこれを解決策と考えています。そして、 'derangr2'は' x [indp] 'を返すべきではありませんか? – Val

+1

私はちょうど 'indp == ind'のところで値を並べ替えてみました。しかし、理論的には、この条件を満たす値が1つだけ残っていると、無限ループが発生する可能性があります。 ...そこで改善はない。 – loki

+0

私は間違っているかもしれませんが、私は 'derangr3'が実行できるとは思いません。定義される前に 'indp'を評価しています。 – Val

関連する問題