Losowo generować Letters Według ich częstotliwości użytkowania?

głosy
10

W jaki sposób można wygenerować losowo liter w zależności od ich częstotliwości korzystania z wspólnej mowie?

Wszelkie pseudo-kod doceniane, ale implementacja w Javie byłoby fantastyczne. W przeciwnym razie po prostu worku we właściwym kierunku byłoby pomocne.

Uwaga: Nie potrzebuję do generowania częstotliwości użytkowania - Jestem pewien, że mogę spojrzeć w górę dość łatwo.

Utwórz 27/01/2010 o 21:11
źródło użytkownik
W innych językach...                            


5 odpowiedzi

głosy
11

Jeden szybki sposób to zrobić byłoby, aby wygenerować listę liter, gdzie każda litera pojawiła się na liście zgodnie z jej częstotliwością. Powiedzieć, czy „e” użyto 25,6% czasu, a lista miał długość 1000, byłoby to 256 „e” s.

Następnie można po prostu losowo wybrać punkty z listy, używając (int) (Math.random() * 1000)do generowania liczb losowych między 0 a 999.

Odpowiedział 27/01/2010 o 21:14
źródło użytkownik

głosy
18

Jestem zakładając, że można przechowywać częstotliwości jako liczb zmiennoprzecinkowych pomiędzy 0 a 1, że Total aby 1.

Najpierw należy przygotować tabelę skumulowanych częstotliwości, tj sumę częstotliwości tego pisma i wszystkich liter przed nim.

Aby uprościć, jeśli zaczniesz z tego podziału częstotliwości:

A  0.1
B  0.3
C  0.4
D  0.2

Twój stół skumulowana częstość będzie:

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)

Teraz wygenerować losową liczbę między 0 a 1 i zobaczyć, gdzie w tym liście, że liczba leży. Wybierz literę, która ma najmniejszy łączny częstotliwość większą niż liczba losowa. Kilka przykładów:

Załóżmy, że losowo wybrać 0,612. To leży między 0,4 a 0,8, czyli między B i C, tak by wybrać C.

Jeśli liczba losowa było 0,039, który jest przed 0.1, czyli przed, więc wybrać A.

Mam nadzieję, że to ma sens, w przeciwnym razie nie krępuj się poprosić o wyjaśnienia!

Odpowiedział 27/01/2010 o 21:20
źródło użytkownik

głosy
4

Nawet pseudo-code, ale możliwym rozwiązaniem jest następujący:

Niech p1, p2, ..., pk być częstotliwości, które chcesz dopasować.

  1. Oblicz łączne częstotliwości P1, P1 + P2, P1 + P2 + P3, ..., 1
  2. Wygenerować losowy jednolite (0,1) x liczba
  3. Sprawdź, jaka przerwa skumulowanych częstotliwości x należy do: jeśli jest pomiędzy, powiedzmy, p1 + .. + PI i p1 + ... + pi + P (i + 1), a następnie wyjście (i + 1) list st

W zależności od sposobu wdrożenia Interval stwierdzenie, procedura jest zwykle bardziej efektywne, jeśli P1, P2, ... są sortowane w kolejności malejącej, ponieważ można zwykle znaleźć przedział zawierający x szybciej.

Odpowiedział 27/01/2010 o 21:20
źródło użytkownik

głosy
5

Co chciałbym zrobić, to skalowanie względem częstotliwości jak liczb zmiennoprzecinkowych takie, że ich suma wynosi 1,0. Wtedy tworzę tablicę skumulowane sumy na piśmie, czyli liczbę, która musi być zwieńczona dostać ten list i wszystkich tych, „poniżej” to. Twierdzą, że częstotliwość sygnału wynosi 10%, b wynosi 2%, a z wynosi 1%; wtedy tabela będzie wyglądać następująco:

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

Następnie wygenerować sobie losową liczbę między 0,0 a 1,0 i zrobić binarne wyszukiwania w tablicy dla pierwszej liczby mniejszej niż liczba losowa. Następnie odebrać list w tej pozycji. Gotowe.

Odpowiedział 27/01/2010 o 21:23
źródło użytkownik

głosy
2

Korzystanie binarne drzewo daje ładny, czysty sposób, aby znaleźć właściwą pozycję. Tutaj zaczynają się frequencymapie, gdzie klawisze są symbole (angielskich liter), a wartości są częstotliwość ich występowania. Ta zostaje odwrócony, a NavigableMapjest utworzony w których klucze są łączne prawdopodobieństwo, a wartości symbole. Sprawia, że wyszukiwanie proste.

  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();
  }
Odpowiedział 27/01/2010 o 22:10
źródło użytkownik

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