Generare casualmente lettere Secondo la loro frequenza d'uso?

voti
10

Come posso generare casualmente le lettere in base alla loro frequenza d'uso nel linguaggio comune?

Ogni pseudo-codice apprezzato, ma un'implementazione in Java sarebbe fantastico. In caso contrario, solo un poke nella giusta direzione, sarebbe utile.

Nota: Non ho bisogno di generare le frequenze di utilizzo - sono sicuro che posso guardare che abbastanza facilmente.

È pubblicato 27/01/2010 alle 21:11
fonte dall'utente
In altre lingue...                            


5 risposte

voti
11

Un modo rapido per farlo sarebbe quello di generare un elenco di lettere, dove ogni lettera è apparso nella lista in accordo con la sua frequenza. Dire, se "e" è stata utilizzata 25,6% del tempo, e la vostra lista aveva lunghezza 1000, avrebbe 256 "e" s.

Poi si può solo scegliere a caso i punti dall'elenco utilizzando (int) (Math.random() * 1000)per generare numeri casuali compresi tra 0 e 999.

Risposto il 27/01/2010 a 21:14
fonte dall'utente

voti
18

Io parto dal presupposto che si memorizzano le frequenze come numeri in virgola mobile tra 0 e 1 che il totale per fare 1.

In primo luogo si dovrebbe preparare una tabella di frequenze cumulative, vale a dire la somma della frequenza di quella lettera e tutte le lettere prima di esso.

Per semplificare, se si inizia con questa distribuzione di frequenza:

A  0.1
B  0.3
C  0.4
D  0.2

La vostra tabella di frequenza cumulativa sarebbe:

A  0.1
B  0.4 (= 0.1 + 0.3)
C  0.8 (= 0.1 + 0.3 + 0.4)
D  1.0 (= 0.1 + 0.3 + 0.4 + 0.2)

Ora generare un numero casuale compreso tra 0 e 1 e vedere dove in questo elenco che il numero si trova. Scegliere la lettera che ha la frequenza cumulativa più piccolo più grande del vostro numero a caso. Qualche esempio:

Diciamo che sceglie in modo casuale 0.612. Questo si trova tra 0,4 e 0,8, vale a dire tra B e C, in modo da sceglierei C.

Se il numero casuale è 0,039, che viene prima di 0,1, vale a dire prima di A, in modo da scegliere A.

Spero che abbia un senso, altrimenti non esitate a chiedere chiarimenti!

Risposto il 27/01/2010 a 21:20
fonte dall'utente

voti
4

Nemmeno uno pseudo-codice, ma un possibile approccio è la seguente:

Lasciate p1, p2, ..., pk essere le frequenze che si desidera abbinare.

  1. Calcolare le frequenze cumulative: p1, p2 p1 +, P1 + P2 + P3, ..., 1
  2. Genera una divisa casuale (0,1) x numero
  3. Controllare che l'intervallo delle frequenze cumulative x appartiene: se è tra, diciamo, p1 + .. + pi e p1 + ... + pi + p (i + 1), producendo quindi la (i + 1) -esima lettera

A seconda di come si sceglie di implementare l'intervallo di accertamento, la procedura di solito è più efficiente se le P1, P2, ... sono ordinati in ordine decrescente, in quanto di solito si trovano l'intervallo contenente x prima.

Risposto il 27/01/2010 a 21:20
fonte dall'utente

voti
5

Cosa farei è scalare le frequenze relative come numeri in virgola mobile tale che la loro somma è pari a 1,0. Poi vorrei creare un array dei cumulativi totali per lettera, vale a dire il numero che deve essere superato per ottenere quella lettera e tutti coloro che "al di sotto" di esso. Dire la frequenza di A è 10%, b è 2% e z è 1%; allora il vostro tavolo sarebbe simile a questa:

0.000 A ; from 0% to 10% gets you an A
0.100 B ; above 10% is at least a B
0.120 C ; 12% for C...
...
0.990 Z ; if your number is >= 99% then you get a Z

Poi si genera voi stessi un numero casuale compreso tra 0,0 e 1,0 e fare una ricerca binaria nella matrice per il primo numero più piccolo di tuo numero casuale. Poi scegliere la lettera in quella posizione. Fatto.

Risposto il 27/01/2010 a 21:23
fonte dall'utente

voti
2

Utilizzando un albero binario ti dà un modo pulito bello trovare la voce giusta. Qui, si inizia con una frequencymappa, dove le chiavi sono i simboli (lettere in inglese), ed i valori sono la frequenza del loro verificarsi. Questo viene invertito, ed una NavigableMapsi crea dove le chiavi sono probabilità cumulativa, ei valori sono simboli. Questo rende la ricerca semplice.

  private final Random generator = new Random();

  private final NavigableMap<Float, Integer> table = 
    new TreeMap<Float, Integer>();

  private final float max;

  public Frequency(Map<Integer, Float> frequency)
  {
    float total = 0;
    for (Map.Entry<Integer, Float> e : frequency.entrySet()) {
      total += e.getValue();
      table.put(total, e.getKey());
    }
    max = total;
  }

  /** 
   * Choose a random symbol. The choices are weighted by frequency.
   */ 
  public int roll()
  {
    Float key = generator.nextFloat() * max;
    return table.higherEntry(key).getValue();
  }
Risposto il 27/01/2010 a 22:10
fonte dall'utente

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more