一般的な会話での使用頻度に応じて文字をランダムに生成するにはどうすればよいですか?
どんな疑似コードでも構いませんが、Java での実装はすばらしいでしょう。それ以外の場合は、正しい方向に突くだけで役立ちます。
注: 使用頻度を生成する必要はありません。簡単に調べることができるはずです。
一般的な会話での使用頻度に応じて文字をランダムに生成するにはどうすればよいですか?
どんな疑似コードでも構いませんが、Java での実装はすばらしいでしょう。それ以外の場合は、正しい方向に突くだけで役立ちます。
注: 使用頻度を生成する必要はありません。簡単に調べることができるはずです。
周波数を 0 と 1 の間の浮動小数点数として保存し、合計すると 1 になると仮定しています。
まず、累積頻度の表、つまり、その文字とその前のすべての文字の頻度の合計を作成する必要があります。
簡単にするために、この度数分布から始めると、次のようになります。
A 0.1
B 0.3
C 0.4
D 0.2
累積頻度表は次のようになります。
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)
ここで、0 から 1 の間の乱数を生成し、その数がこのリストのどこにあるかを確認します。乱数よりも大きい累積度数が最も小さい文字を選択します。いくつかの例:
ランダムに 0.612 を選択するとします。これは 0.4 と 0.8 の間、つまり B と C の間にあるので、C を選択します。
乱数が 0.039 の場合、それは 0.1 の前、つまり A の前にあるので、A を選択します。
それが理にかなっていることを願っています。それ以外の場合は、お気軽に説明を求めてください!
私がすることは、合計が 1.0 になるように相対周波数を浮動小数点数としてスケーリングすることです。次に、文字ごとの累積合計の配列を作成します。つまり、その文字を取得するために上になければならない数と、その「下」のすべての数です。A の頻度が 10%、b が 2%、z が 1% だとします。次に、テーブルは次のようになります。
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
次に、0.0 から 1.0 の間の乱数を自分で生成し、配列内でバイナリ検索を実行して、乱数より小さい最初の数を探します。次に、その位置にある文字を選択します。終わり。
疑似コードでさえありませんが、可能なアプローチは次のとおりです。
p1、p2、...、pk を一致させたい周波数とします。
間隔検索の実装方法によっては、p1、p2、... が降順でソートされている場合、通常は x を含む間隔がすぐに見つかるため、この手順はより効率的です。
二分木を使用すると、適切なエントリを見つけるための優れたクリーンな方法が得られます。ここでfrequency
は、キーが記号(英語の文字)であり、値がそれらの出現頻度であるマップから始めます。これは反転NavigableMap
され、キーが累積確率であり、値がシンボルである場合にaが作成されます。これにより、検索が簡単になります。
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();
}