実際の分布から引き出すことができるのに、なぜべき乗則の分布に落ち着くのですか?
LastNamesテーブルを変更して、より一般的な名前の個人の実際の数を表す数値を含む数値列を含めることをお勧めします。おそらく、表現のパーセントごとに10,000など、小さいが比例したスケールの数値が必要になります。
リストは次のようになります:(
質問で言及された3つの名前を除いて、私はWhite、Johnsonなどについて推測しています)
Smith 0
White 10,060
Johnson 19,123
Williams 28,456
...
Sanders 200,987
..
Alderink 999,997
そして名前の選択は
SELECT TOP 1 [LastName]
FROM [LastNames] as LN
WHERE LN.[number_described_above] < ROUND(100000 * RAND(), 0)
ORDER BY [number_described_above] DESC
これは、[一様分布]乱数を超えない数の名を選択することです。クエリがどのように未満を使用し、 desc -endの順序で順序付けているかに注意してください。これにより、最初のエントリ(Smith)が選択されることが保証されます。別の方法は、ゼロではなく10,060でスミスでシリーズを開始し、この値よりも小さいランダムドローを破棄することです。
上記の境界管理(10,060ではなくゼロから開始)の問題を除けば、このソリューションは、これまでの他の2つの応答とともに、この質問で参照されている質問に対するdmckeeの回答で提案されたものと同じです。基本的には、CDF(累積分布関数)を使用するという考え方です。
編集:実際の分布ではなく数学関数
を使用することを主張する場合、以下は、実際の分布の「ロングテール」形状を何らかの形で伝えるべき乗則関数を提供する必要があります。@PwrCoef値(ところで整数である必要はありません)を微調整したい場合があります。基本的に係数が大きいほど、関数はリストの先頭に偏っています。
DECLARE @PwrCoef INT
SET @PwrCoef = 2
SELECT 88799 - ROUND(POWER(POWER(88799.0, @PwrCoef) * RAND(), 1.0/@PwrCoef), 0)
注:
-上記の関数の余分な「.0」は、SQLに整数演算ではなくfloat演算を実行させるために重要です。
-88799から電力計算を減算する理由は、計算の分布が、数値がスケールの終わりに近づくほど、描画される可能性が高くなるためです。逆の順序でソートされている家族名のリスト(ほとんどの場合、名前が最初)、この減算が必要です。
たとえば、3の累乗を想定すると、クエリは次のようになります。
SELECT [LastName]
FROM [LastNames] as LN
WHERE LN.[Rank]
= 88799 - ROUND(POWER(POWER(88799.0, 3) * RAND(), 1.0/3), 0)
これは、最後の行を除いて、質問からのクエリです。
再編集:
国勢調査データで明らかなように、実際の分布を見ると、曲線は非常に急勾配であり、非常に大きな電力係数が必要になります。これにより、上記の単純な式でオーバーフローや極端な丸め誤差が発生します。 。
より賢明なアプローチは、いくつかの層で操作することです。つまり、累積分布の3分の3(または4分の4など)のそれぞれで同数のドローを実行することです。これらの各パーツリスト内で、べき乗則関数を使用して描画します。係数は同じですが、範囲が異なります。
たとえば、
3分の1とすると、リストは次のように分割されます。
- 最初の3分の1=スミスからアルバラドまでの425の名前
- 2番目の3番目=6,277の名前、fromからGainer
- 最後の3分の1=フリスビーから最後まで、82,097の名前
たとえば、1,000個の名前が必要な場合は、リストの上位3分の1から334、2番目の3分の1から333、最後の3分の1から333を描画します。
3分の1ごとに、同様の式を使用します。おそらく、最初の3分の1の電力係数が大きくなります(リスト内の以前の名前を優先することに本当に関心があり、相対頻度がより統計的に関連している場合もあります)。3つの選択クエリは次のようになります。
-- Random Drawing of a single Name in top third
-- Power Coef = 12
SELECT [LastName]
FROM [LastNames] as LN
WHERE LN.[Rank]
= 425 - ROUND(POWER(POWER(425.0, 12) * RAND(), 1.0/12), 0)
-- Second third; Power Coef = 7
...
WHERE LN.[Rank]
= (425 + 6277) - ROUND(POWER(POWER(6277.0, 7) * RAND(), 1.0/7), 0)
-- Bottom third; Power Coef = 4
...
WHERE LN.[Rank]
= (425 + 6277 + 82097) - ROUND(POWER(POWER(82097.0, 4) * RAND(), 1.0/4), 0)