偏置随机数发生器的可能方法是什么?

时间:2011-07-29 09:02:47

标签: c++ prng

我构建了一个单词生成器,它选择一个长度,然后随机选择字母表中的字母来组成单词。

该程序有效但99%的输出都是垃圾,因为它没有观察到英语的构造,我正在使用x和z获得尽可能多的单词。

我可以选择偏置RNG,以便更频繁地使用普通字母。

我正在使用随时间播种的stl()。

8 个答案:

答案 0 :(得分:5)

输出仍然是垃圾,因为偏置随机数生成器不足以构造正确的英语单词。但是偏向rng的一种方法是:

  1. 在大型英文文本(语料库)中创建字母出现的直方图。你会得到500'e',3'x',1'q',450'a',200'b'等等。
  2. 将间隔划分为每个字母获得切片的范围,切片的长度是间隔中出现的数量。 a得到[0-450],b [450,650],...,q [3500,3501]。
  3. 生成介于0和间隔总长度之间的随机数,并检查其落地位置。 450-650之内的任何数字都会给你一个b,但只有3500给你一个'q'。

答案 1 :(得分:2)

一种方法是使用字母频率。对于每个字母定义一个范围:a = [0,2](如果字母'a'有2%的机会被使用),b = [2,5](3%几率),依此类推..然后生成0到100之间的随机数,然后选择一个字母。

另一种方法是使用非确定性有限自动机,您可以在其中定义某些转换(您可以解析圣经并建立您的概率)。所以你有很多这样的过渡:例如从'a'到'b'的过渡是5%。然后你走过自动机并生成一些单词。

我刚看到正确的术语是马尔可夫链,这可能比NFA更好。

答案 2 :(得分:1)

您可以对某些正文进行n-gram分析,并将其作为偏见的基础。您可以通过字母或音节来完成此操作。通过音节进行分析可能更复杂。

通过信件来做,很容易。您遍历源文本中的每个字符并跟踪您遇到的最后n-1个字符。然后,对于每个下一个字符,您将最后的n-1个字符和这个新字符(n-gram)添加到您的频率表中。

这张频率表是什么样的?您可以使用将n-gram映射到其频率的映射。但是这种方法对于我建议的算法并不是很好。为此,最好将每个(n-1)-grams映射到n-gram的最后一个字母到其频率的映射。类似于:std::map<std::string, std::map<char,int>>

进行分析并收集统计数据后,算法将如下所示:

  1. 选择一个随机的起始n-gram。您之前的分析可能包含加权数据,其中的字母通常以单词开头;
  2. 从以前的n-1个字母开头的所有n-gram中,选择一个随机的最后一个字母(考虑分析中的权重);
  3. 重复,直至到达单词的结尾(使用预定义的长度或关于单词结束频率的数据);
  4. 要从一组具有不同权重的值中选择随机值,您可以从设置累积频率表开始。然后你选择一个小于频率之和的随机数,看看它下降的间隔。

    例如:

    • A发生了10次;
    • B发生了7次;
    • C发生了9次;

    您构建下表:{A:10,B:17,C:26}。你选择1到26之间的数字。如果它小于10,它是A;如果它大于或等于10,但小于17,则为B;如果它大于17,那就是C。

答案 3 :(得分:0)

您可能希望使用英语的字母频率来获得更真实的输出:http://en.wikipedia.org/wiki/Letter_frequency

但是如果你想要可说的单词,你应该从音节中生成它们。您可以在线查找更多信息,例如在这里:http://spell.psychology.wustl.edu/SyllStructDistPhon/CVC.html

答案 4 :(得分:0)

如果您只想更改单词中的字母频率,而无需进一步的词法分析(如qu对),请获取英语字母频率列表。

然后创建一个加权随机生成器,它将有更多机会输出e(偶数为1/7)x(1000左右)。

生成加权随机生成器(rand生成整数,IIRC):
1.标准化字母频率,使它们都是整数(对于维基百科频率基本上乘以100000)
2.制作某种查找表,在每个字母的位置分配一定的范围,如下表

letter  | weight  |  start   |    end
a       |   8.17% |      0   |   8167
b       |   1.49% |   8168   |   9659
c       |   2.78% |   9660   |  12441
d       |   4.25% |  12442   |  16694
e       |  12.70% |  16695   |  29396
f       |   2.23% |  29397   |  31624
g       |   2.02% |  31625   |  33639
.....
z       |   0.07% | 99926    |  99999

3。生成0到99999之间的随机数,并使用它来查找相应的字母。这样,您将拥有正确的字母频率。

答案 5 :(得分:0)

您可以导出Markov Model阅读源文本,然后生成与“源”相似的单词。

这也适用于从单词生成句子。好吧,有点工作。

答案 6 :(得分:0)

首先,你需要一张包含字母及其重量的表格 像:

struct WeightedLetter
{
    char letter;
    int  weight;
};

static WeightedLetter const letters[] =
{
    { 'a', 82 },
    { 'b', 15 },
    { 'c', 28 },
    //  ...
};

char getLetter()
{
    int totalWeight = 0;
    for ( WeightedLetter const* iter = begin( letters );
            iter != end( letters );
            ++ iter ) {
        totalWeight += iter->weight;
    }
    int choice = rand() % totalWeight;
                // but you probably want a better generator
    WeightedLetter const* result = begin( letters );
    while ( choice > result->weight ) {
        choice -= result->weight;
        ++ result;
    }
    return result->letter;
}

这只是我的头脑,所以它可能包含错误; 至少,第二个循环需要一些验证。但它 应该给你基本的想法。

当然,这仍然不会产生类似英语的单词。该 序列“uq”和“qu”一样可能,没有什么可以阻止的 一个没有元音的单词,或一个只带元音的十个字母的单词。 English Phonology上的维基百科页面提供了一些关于哪些组合可以在哪里发生的良好信息,但它没有任何统计数据。另一方面,如果你试图弥补可能的话,比如Jabberwocky,那么这可能不是一个问题:选择一个随机数的音节,从1到最大,然后是一个开始,一个核和一个尾声。 (不要忘记发作和尾声可能是空的。)

答案 7 :(得分:0)

如果您想创建可发音的单词,请不要尝试将字母连接在一起。

加入声音。制作一个可供选择的声音列表:“abe”,“ape”,“gre”等