有名なフィッシャー-イェーツシャッフルアルゴリズムを使用して、長さNの配列Aをランダムに並べ替えることができます。
For k = 1 to N
Pick a random integer j from k to N
Swap A[k] and A[j]
私が何度も何度も犯さないように言われたよくある間違いはこれです:
For k = 1 to N
Pick a random integer j from 1 to N
Swap A[k] and A[j]
つまり、kからNまでのランダムな整数を選択する代わりに、1からNまでのランダムな整数を選択します。
この間違いをするとどうなりますか?結果の順列が均一に分布していないことは知っていますが、結果の分布がどうなるかについてどのような保証があるのかわかりません。特に、要素の最終的な位置の確率分布の式を持っている人はいますか?
経験的アプローチ。
Mathematicaで誤ったアルゴリズムを実装しましょう:
p = 10; (* Range *)
s = {}
For[l = 1, l <= 30000, l++, (*Iterations*)
a = Range[p];
For[k = 1, k <= p, k++,
i = RandomInteger[{1, p}];
temp = a[[k]];
a[[k]] = a[[i]];
a[[i]] = temp
];
AppendTo[s, a];
]
次に、各整数が各位置にある回数を取得します。
r = SortBy[#, #[[1]] &] & /@ Tally /@ Transpose[s]
結果の配列で3つの位置を取り、その位置の各整数の度数分布をプロットしてみましょう。
位置1の場合、周波数分布は次のとおりです。
ポジション5(中央)の場合
そしてポジション10(最後)の場合:
ここに、すべての位置の分布が一緒にプロットされています。
ここでは、8つのポジションにわたるより良い統計があります。
いくつかの観察:
これらのプロパティは、同じポイント(最初のプロパティ)と最後の水平線(3番目のプロパティ)からのすべての線の始点を見て視覚化できます。
2番目のプロパティは、次の行列表現の例からわかります。ここで、行は位置、列は居住者番号、色は実験確率を表します。
100x100マトリックスの場合:
編集
楽しみのために、2番目の対角要素の正確な式を計算しました(最初は1/nです)。残りはできますが、大変な作業です。
h[n_] := (n-1)/n^2 + (n-1)^(n-2) n^(-n)
N = 3から6まで検証された値({8/27、57/256、564/3125、7105/46656})
編集
@wnoise answerで一般的な明示的な計算を少し実行すると、もう少し情報を得ることができます。
1/nをp [n]に置き換えると、計算は評価されないままになります。たとえば、n = 7の行列の最初の部分を取得します(クリックすると大きな画像が表示されます)。
これは、nの他の値の結果と比較した後、マトリックス内のいくつかの既知の整数シーケンスを識別しましょう。
{{ 1/n, 1/n , ...},
{... .., A007318, ....},
{... .., ... ..., ..},
... ....,
{A129687, ... ... ... ... ... ... ..},
{A131084, A028326 ... ... ... ... ..},
{A028326, A131084 , A129687 ... ....}}
これらのシーケンス(場合によっては符号が異なる)は、すばらしい http://oeis.org/ にあります。
一般的な問題を解決することはより困難ですが、これが始まりであることを願っています
あなたが言及する「よくある間違い」は、ランダムな転置によるシャッフルです。この問題は、DiaconisとShahshahaniによって ランダム転置によるランダム順列の生成(1981) で詳細に研究されました。それらは、停止時間と均一性への収束の完全な分析を行います。論文へのリンクが見つからない場合は、私にメールを送ってください。コピーを転送できます。それは実際には楽しい読み物です(Persi Diaconisのほとんどの論文がそうであるように)。
配列に繰り返しエントリがある場合、問題は少し異なります。恥知らずなプラグとして、このより一般的な問題は、私自身、DiaconisとSoundararajanによって A Rule of Thumb for Riffle Shuffling(2011) の付録Bで対処されています。
まあ言ってみれば
a = 1/N
b = 1-a
i
がk
番目の要素と交換した後の確率行列です。つまり、「k
スワップ後のi
はどこにありますか?」という質問への回答です。例B(3)= (0 0 1 0 ... 0)
とB1(3)= (a 0 b 0 ... 0)
。あなたが欲しいのはBですN(k)すべてのkに対して。次に、
しかし、BN(k = 1..N)は単位行列を形成し、与えられた要素iが最後に位置jにある確率は、行列の行列要素(i、j)によって与えられます。
たとえば、N = 4の場合:
N = 500の図として(色レベルは100 *確率):
パターンはすべてのN> 2で同じです。
私は以前にこの質問を見たことがあることを知っていました...
" この単純なシャッフルアルゴリズムが偏った結果を生成するのはなぜですか?単純な理由は何ですか? "回答には多くの良いものがあります。特に コーディングに関するJeff Atwoodのブログ)へのリンクがあります。ホラー 。
すでにお察しのとおり、@ belisariusの回答に基づいて、正確な分布はシャッフルされる要素の数に大きく依存します。 6要素デッキのAtwoodのプロットは次のとおりです。
なんて素敵な質問でしょう。完全な答えがあればいいのにと思います。
フィッシャー-イェーツは、最初の要素を決定すると、それをそのままにしておくので、分析するのに最適です。偏った人は、要素を任意の場所に繰り返し交換することができます。
確率分布に線形に作用する確率遷移行列としてアクションを記述することにより、マルコフ連鎖と同じ方法でこれを分析できます。ほとんどの要素はそのままになり、対角線は通常(n-1)/ nです。パスkで、そのままにしないと、要素k(または要素kの場合はランダム要素)と交換されます。これは、行または列kのいずれかで1 /(n-1)です。行kと列kの両方の要素も1 /(n-1)です。 kが1からnになるように、これらの行列を乗算するのは簡単です。
最後のパスは最後の場所を他の要素と同じように交換するため、最後の場所の要素は元々どこにでもあった可能性が同じであることを私たちは知っています。同様に、最初の要素はどこにでも同じように配置される可能性があります。この対称性は、転置が行列の乗算の順序を逆にするためです。実際、行列は、行iが列(n + 1-i)と同じであるという意味で対称です。それを超えて、数字はあまり明白なパターンを示していません。これらの正確な解は、ベリサリウスによって実行されたシミュレーションとの一致を示しています。スロットiでは、jがiに上がると、jを取得する確率が低下し、i-1で最小値に達し、次にiで最大値にジャンプします。 jがnに達するまで減少します。
数学では、私は各ステップを次のように生成しました
step[k_, n_] := Normal[SparseArray[{{k, i_} -> 1/n,
{j_, k} -> 1/n, {i_, i_} -> (n - 1)/n} , {n, n}]]
(どこにも文書化されていませんが、最初の一致ルールが使用されます。)最終的な遷移行列は次のように計算できます。
Fold[Dot, IdentityMatrix[n], Table[step[m, n], {m, s}]]
ListDensityPlot
は便利な視覚化ツールです。
編集(ベリサリウスによる)
ただの確認。次のコードは、@ Eelvexの回答と同じ行列を示します。
step[k_, n_] := Normal[SparseArray[{{k, i_} -> (1/n),
{j_, k} -> (1/n), {i_, i_} -> ((n - 1)/n)}, {n, n}]];
r[n_, s_] := Fold[Dot, IdentityMatrix[n], Table[step[m, n], {m, s}]];
Last@Table[r[4, i], {i, 1, 4}] // MatrixForm
これをさらに調べてみると、この分布は詳細に研究されていることがわかりました。これが興味深い理由は、この「壊れた」アルゴリズムがRSAチップシステムで使用されている(または使用されていた)ためです。
セミランダム転置によるシャッフル では、Elchanan Mossel、Yuval Peres、およびAlistair Sinclairが、これとより一般的なクラスのシャッフルを研究しています。その論文の結論は、ほぼランダムな分布を達成するためにlog(n)
壊れたシャッフルが必要であるように思われます。
In3つの疑似ランダムシャッフルのバイアス(Aequationes Mathematicae、22、1981 、268-292)、EthanBolkerとDavidRobbinsはこのシャッフルを分析し、1回のパス後の均一性までの全変動距離が1であることを確認します。これは、それがまったくランダムではないことを示しています。それらは無症候性の分析も行います。
最後に、LaurentSaloff-CosteとJessicaZunigaは、不均一なマルコフ連鎖の研究で素晴らしい上限を見つけました。
フィッシャー-イェーツシャッフルに関するウィキペディアのページ には、その場合に何が起こるかについての説明と例があります。
確率行列 を使用して分布を計算できます。行列A(i、j)が、元々位置iにあったカードが位置jで終わる確率を表すとします。次に、k番目のスワップはAk(i,j) = 1/N
で与えられる行列Akを持ちます(i == k
またはj == k
の場合)(位置kのカードはどこにでも配置でき、どのカードも同じ確率で位置kに配置できます)、Ak(i,i) = (N - 1)/N
すべてのi != k
(他のすべてのカードは確率(N-1)/ Nで同じ場所にとどまります)および他のすべての要素はゼロです。
完全なシャッフルの結果は、行列AN ... A1
の積によって与えられます。
確率の代数的記述を探していると思います。上記の行列積を拡張することで取得できますが、かなり複雑になると思います。
更新:上記のwnoiseの同等の答えを見つけました!おっと...
この質問は、言及された壊れたシャッフルの インタラクティブな視覚的マトリックス図 分析を懇願しています。そのようなツールはページにあります シャッフルしますか?-ランダムコンパレータが悪い理由 マイクボストックによる。
Bostockは、ランダムコンパレータを分析する優れたツールをまとめました。そのページのドロップダウンで、ナイーブスワップ(ランダム↦ランダム)を選択して、壊れたアルゴリズムとそれが生成するパターンを確認します。
彼のページは、ロジックの変更がシャッフルされたデータに与える即時の影響を確認できるため、有益です。例えば:
不均一で非常に偏ったシャッフルを使用したこのマトリックス図は、次のようなコードでナイーブスワップ(「1からN」から選択)を使用して作成されます。
function shuffle(array) {
var n = array.length, i = -1, j;
while (++i < n) {
j = Math.floor(Math.random() * n);
t = array[j];
array[j] = array[i];
array[i] = t;
}
}
ただし、「kからN」まで選択する、バイアスのないシャッフルを実装すると、次のような図が表示されます。
ここで、分布は均一であり、次のようなコードから生成されます。
function FisherYatesDurstenfeldKnuthshuffle( array ) {
var pickIndex, arrayPosition = array.length;
while( --arrayPosition ) {
pickIndex = Math.floor( Math.random() * ( arrayPosition + 1 ) );
array[ pickIndex ] = [ array[ arrayPosition ], array[ arrayPosition ] = array[ pickIndex ] ][ 0 ];
}
}
これまでの優れた回答は配布に集中していますが、「この間違いをするとどうなりますか?」-これが私ですまだ回答がないので、これについて説明します。
Knuth-Fisher-Yatesシャッフルアルゴリズムは、n個の要素から1つを選択し、次にn-1個の残りの要素から1つを選択します。
A1から1つの要素を削除してa2に挿入する2つの配列a1とa2で実装できますが、説明されているように、アルゴリズムはその場で実行します(つまり、1つの配列のみが必要です) ここで (Google: "Shuffling Algorithms Fisher-Yates DataGenetics")非常にうまくいっています。
要素を削除しない場合は、要素を再度ランダムに選択して、偏ったランダム性を生成できます。これはまさにあなたが説明している2番目の例が行うことです。最初の例であるKnuth-Fisher-Yatesアルゴリズムは、kからNまで実行されるカーソル変数を使用します。これは、どの要素が既に取得されているかを記憶しているため、要素を複数回選択することを回避します。