Domanda

Io fondamentalmente bisogno la risposta a questa domanda SO che fornisce una distribuzione di legge di potenza , tradotto in T-SQL per me.

voglio tirare un cognome, una alla volta, da un censimento ha fornito la tabella di nomi . Voglio ottenere più o meno la stessa distribuzione come avviene nella popolazione. Il tavolo ha 88,799 nomi ordinati per frequenza. "Smith" è il numero 1 con la frequenza 1.006%, "Alderink" è rango 88.799 con una frequenza di 1,7 x 10 ^ -6. "Sanders" è rango 75 con una frequenza di 0,100%.

La curva non deve adattarsi con precisione a tutti. Dammi solo circa l'1% "Smith" e circa 1 su un milione "Alderink"

Ecco quello che ho finora.

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

Ma questo, naturalmente, produce una distribuzione uniforme.

Ti prometto io sarò ancora cercando di capire questo fuori me stesso per il momento in una persona più intelligente risponde.

È stato utile?

Soluzione

Perché accontentarsi per la distribuzione legge di potenza quando si può attingere alla effettiva distribuzione?

Vi suggerisco di alterare la tabella lastnames per includere una colonna numerica che conterrebbe un valore numerico che rappresenta il numero effettivo di indivuduals con un nome che è più comune. Probabilmente si vorrà un numero su una scala più piccola, ma proporzionale, dire, forse 10.000 per ogni punto percentuale di rappresentanza.

La lista sarebbe quindi cercare qualcosa di simile:
(Oltre alle 3 nomi citati nella domanda, sto cercando di indovinare su White, Johnson et al)

Smith          0   
White     10,060
Johnson   19,123
Williams  28,456
...
Sanders  200,987
..
Alderink 999,997

E la selezione nome sarebbe stato

SELECT TOP 1 [LastName]
FROM [LastNames] as LN
WHERE LN.[number_described_above] < ROUND(100000 * RAND(), 0)
ORDER BY [number_described_above] DESC

Quello di raccogliere il primo nome che il numero non supera il [uniforme distribuzione] di numeri casuali. Si noti come la query, usi meno e l'ordine in desc ordine -ending; tale volontà garanzia che il primissimo ingresso (Smith) viene raccolto. L'alternativa sarebbe di iniziare la serie con Smith a 10.060 anziché zero e scartare casuale attira inferiore a questo valore.

A parte la questione di gestione di delimitazione (a partire da zero anziché 10.060) sopra menzionati, questa soluzione, insieme con gli altri due risposte finora, sono gli stessi come quello proposto in dmckee ' s risposta alla domanda si fa riferimento in questa domanda. Essenzialmente l'idea è quella di utilizzare il CDF ( funzione distribuzione cumulativa ).


Modifica :
Se ti ostini a usare una funzione matematica, piuttosto che l'effettiva distribuzione , il seguente dovrebbe fornire una funzione di legge di potenza che avrebbe in qualche modo trasmettere la forma a "coda lunga" della distribuzione vera e propria. Si può wan di modificare il valore di @PwrCoef (che BTW non deve essere un numero intero), in sostanza, il più grande è il coeficient, tanto più distorta all'inizio della lista della funzione è.

DECLARE @PwrCoef INT
SET @PwrCoef = 2
SELECT 88799 - ROUND(POWER(POWER(88799.0, @PwrCoef) * RAND(), 1.0/@PwrCoef), 0)

Note:
  - l'extra" 0,0" nella funzione di cui sopra sono importanti per forzare SQL per eseguire le operazioni galleggiante piuttosto che le operazioni di interi
.   - il motivo per cui si sottrae il calcolo della potenza da 88.799 è che la distribuzione del calcolo è tale che quanto più un numero è più vicino alla fine della nostra scala, la più probabile è da trarre. L'elenco dei nomi di famiglia da ordinare in ordine inverso (molto probabilmente i nomi prima), abbiamo bisogno di questa sottrazione.

Supponendo una potenza di, diciamo, 3 la query sarebbe quindi simile a

SELECT [LastName]
FROM [LastNames] as LN
WHERE LN.[Rank]
     = 88799 - ROUND(POWER(POWER(88799.0, 3) * RAND(), 1.0/3), 0)

Qual è la query dalla questione, tranne per l'ultima riga.

Re-Edit :
Guardando alla distribuzione effettiva, come risulta nei dati censimento, la curva è estremamente ripida e richiederebbe un grande coefficiente di potenza, che a sua volta causare overflow e / o errori estreme arrotondamento nella naive formula indicata sopra.
Un approccio più ragionevole potrebbe essere quella di operare in diversi livelli cioè di eseguire un numero uguale di estrazioni in ciascuna delle, diciamo, tre terzi (o quattro quarti o ...) della distribuzione cumulativa; all'interno di ciascuno di questi elenco delle parti, vorremmo disegnare utilizzando una funzione di legge di potenza, possibilmente con la stessa coeficient, ma con diversi range.
Per esempio
Supponendo terzi, l'elenco si divide come segue:

  • primo terzo = 425 nomi, da Smith a Alvarado
  • secondo terzo = 6.277 nomi, da a Gainer
  • ultimo terzo = 82,097 nomi, da Frisby alla fine

Se dovessimo necessità, diciamo, 1.000 nomi, ci piacerebbe disegnare 334 dalla cima terzo della lista, 333 dal secondo terzo e 333 dal l'ultimo terzo.
Per ciascuno dei terzi avremmo usare una formula simile, magari con un coeficient potere più grande per il primo terzo (stati Were sono realmente interessati a favorire i nomi precedenti nella lista, e anche il luogo dove il relativo le frequenze sono più statisticamente rilevante). I tre query di selezione potrebbe somigliare al seguente:

-- 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)

Altri suggerimenti

Invece di memorizzare il PDF come rango, memorizzare il CDF (la somma di tutte le frequenze fino a quel nome, a partire dal Aldekirk).

Quindi modificare la vostra selezione per recuperare la prima LN con maggiore rango del tuo risultato della formula.

Ho letto la questione come "ho bisogno di ottenere un flusso di nomi che rispecchierà la frequenza del cognome dal US Census 1990"

I potrebbe avere leggere la domanda un po 'diverso rispetto agli altri suggerimenti e anche se una risposta è stata accettata, e una risposta attraverso lo è, io contribuirà la mia esperienza con il censimento del cognome.

I aveva scaricato gli stessi dati del censimento del 1990. Il mio obiettivo era quello di produrre un gran numero di nomi da presentare per il test di ricerca durante il test delle prestazioni di un record app medica. Ho inserito gli ultimi nomi e la percentuale di frequenza in una tabella. Ho aggiunto una colonna e riempito con un intero che era il prodotto di "nomi totale necessaria frequenza *". I dati di frequenza del censimento non aggiungere fino a esattamente il 100% quindi il mio numero totale di nomi è stato anche un po 'a corto del requisito. Sono stato in grado di correggere il numero selezionando nomi casuali dall'elenco e aumentando il loro numero fino a quando ho avuto esattamente il numero richiesto, il conteggio ha aggiunto in modo casuale mai ammounted a più di 0,05% del totale di 10 milioni.

ho generato 10 milioni di numeri casuali nella gamma da 1 a 88799. Con ogni numero a caso vorrei scegliere quel nome dall'elenco e decrementare il contatore per quel nome. Il mio approccio è stato quello di simulare trattare un mazzo di carte, tranne mio mazzo aveva molte carte più distinti e una serie variando di ogni carta.

Ti memorizzare le frequenze effettive con i ranghi?

La conversione l'algebra da quella risposta accettata a MySQL non è fastidio, se si sa cosa valori da utilizzare per n. y sarebbe quello che si ha attualmente ROUND(88799 * RAND(), 0) e x0,x1 = 1,88799 penso, anche se potrei fraintendere. La matematica solo operatore non standard coinvolti da una prospettiva T-SQL è ^ che è appena POWER(x,y) == x^y.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top