我正在进行一个大型的机器学习/自然语言处理项目,但在其中的一个小部分遇到了困难。(如果你想知道我具体在做什么,请私信我。)
我尝试用Javascript编写一个程序,通过使用字母表中的所有字母来学习生成有效的单词。
我有一个包含50万个不同单词的数据库。这是一个大型的JS对象,结构如下(单词是德语的):
database = { "um": {id: 1, word: "um", freq: 10938}, "oder": {id: 2, word: "oder", freq: 10257}, "Er": {id: 3, word: "Er", freq: 9323}, ...}
"freq"
显然表示频率。(这个值有时可能会变得重要,但我目前没有使用它,所以可以忽略。)
我的程序当前的工作方式是:在第一次迭代中,它会生成一个完全随机的单词,长度在2到13个字母之间,并在数据库中搜索这个单词。如果找到这个单词,单词中的每个字母都会得到一个好的评分;如果没有找到,它们会得到一个差的评分。单词的长度也会被评分。如果单词有效,其长度会得到好的评分;如果无效,其长度会得到差的评分。
在第一次迭代之后的迭代中,它不会生成使用随机字母和随机长度的单词。它会根据字母和单词长度的评分使用概率来生成单词。
例如,假设在前100次迭代后,它找到了单词“the”、“so”和“if”。那么字母“t”、“h”、“e”和字母“s”、“o”,以及字母“i”、“f”都会被评为好评,长度为2和3的单词也被评为好评。因此,在下一次迭代中生成的单词更有可能包含这些被评为好的字母,而不是被评为差的字母。
当然,程序还会检查当前生成的单词是否已经生成过,如果是,那么这个单词不会再次被评分,并且会生成一个新的单词。
理论上,它应该能自己学习到最佳的字母频率和最佳的单词长度频率,有时只生成有效的单词。
是的。当然这行不通。在最初的几次迭代中,它会有所改善,但一旦它找到所有长度为2的单词后,效果就会变差。我认为我的整个方法可能有问题。我实际上已经尝试过,并为你准备了5000次迭代后的(不太漂亮的)图表:
红色线条:生成的错误单词
绿色线条:生成的正确单词
是的。这里有什么问题?我在机器学习方面做错了什么吗?你有解决方案吗?有什么算法或trie系统?
附注:我知道这个,但它不是用JS写的,我不理解它,也无法对此发表评论。
回答:
另一种方法是使用马尔可夫模型。
首先,统计字典中的字母频率和单词长度频率。然后,为了创建一个单词:
- 选择一个加权随机数(见下文),介于1和现有最大单词长度之间。这就是你要生成的字母数量。
- 对于单词中的每个字母,选择一个加权随机字母并将其添加到单词中。
这是一个零阶马尔可夫模型。它基于语料库中出现的字母频率。它可能会给你与你目前的系统相似的结果。
你会从一阶马尔可夫模型中得到更好的结果,在这种模型中,你不是计算字母频率,而是计算二元组(两个字母的排列组合)频率。因此,要选择第一个字母,你只从用于开始单词的二元组中选择。对于后续的字母,你选择一个跟随之前生成的字母的字母。这将比零阶模型给出更好的结果。
二阶模型的效果出奇的好。请看我的博客文章,Shakespeare vs. Markov,以获取一个例子。
加权随机数是一个“随机”选择的数字,但它反映了某种分布。例如,在英语中,字母‘e’大约出现12.7%的时间。‘t’出现9.06%的时间,等等。参见https://en.wikipedia.org/wiki/Letter_frequency。所以你希望你的加权随机数生成器的输出能够近似这种分布。或者,在你的情况下,你希望它近似你语料库中的分布。参见加权随机数,以了解如何实现这一点的示例。