2

基本的に、べき乗則の分布を提供し、 T-SQLに変換されるこのSOの質問に対する答えが必要です。

国勢調査で提供された名前のテーブルから、一度に1つずつ姓を取得したいと思います。母集団で発生するのとほぼ同じ分布を取得したいと思います。この表には、頻度でランク付けされた88,799の名前があります。「Smith」はランク1で頻度は1.006%、「Alderink」はランク88,799で頻度は1.7 x 10^-6です。「サンダース」はランク75で、頻度は0.100%です。

曲線は正確にフィットする必要はありません。約1%の「スミス」と100万分の1の「アルデリンク」をください

これが私がこれまでに持っているものです。

SELECT [LastName]
FROM [LastNames] as LN
WHERE LN.[Rank] = ROUND(88799 * RAND(), 0)

しかし、これはもちろん一様分布をもたらします。

賢い人が反応するまでに、私はまだこれを自分で理解しようとしていると約束します。

4

4 に答える 4

3

実際の分布から引き出すことができるのに、なぜべき乗則の分布に落ち着くのですか?

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)
于 2010-11-24T20:06:15.453 に答える
2

pdfをランクとして保存する代わりに、CDF(Aldekirkから始まるその名前までのすべての頻度の合計)を保存します。

次に、選択を変更して、数式の結果よりもランクが高い最初のLNを取得します。

于 2010-11-24T20:05:58.220 に答える
1

私は質問を「1990 年の米国国勢調査の姓の頻度を反映する名前のストリームを取得する必要がある」と読みました。

私は質問を他の提案とは少し異なって読んだかもしれません.回答は受け入れられましたが、非常にスルーされた回答ですが、国勢調査の姓に関する私の経験を提供します.

私は 1990 年の国勢調査から同じデータをダウンロードしました。私の目標は、医療記録アプリのパフォーマンス テスト中に、検索テスト用に送信される多数の名前を作成することでした。姓と頻度の割合を表に挿入しました。列を追加し、「必要な名前の合計 * 頻度」の積である整数を入力しました。国勢調査からの頻度データの合計が正確に 100% にならなかったため、名前の総数も要件を少し下回りました。リストからランダムな名前を選択し、正確に必要な数になるまでその数を増やすことで、数を修正することができました。ランダムに追加された数は、合計 1,000 万の 0.05% を超えることはありませんでした。

1 から 88799 までの範囲の乱数を 1000 万個生成しました。乱数ごとに、リストからその名前を選び、その名前のカウンターを減らします。私のアプローチは、カードのデッキをシミュレートすることでしたが、デッキにはより多くの異なるカードがあり、各カードの数はさまざまでした。

于 2010-11-25T04:02:29.697 に答える
0

実際の頻度をランクとともに保存しますか?

に使用する値がわかっている場合は、受け入れられた回答からMySQLに代数を変換するのは面倒ではありませんny私はそれを誤解するかもしれませんが、あなたが現在持っているものでROUND(88799 * RAND(), 0)あり、x0,x1 = 1,88799私は思います。T-SQLの観点から関係する唯一の非標準の数学演算子は、^これだけPOWER(x,y) == x^yです。

于 2010-11-24T20:05:46.600 に答える