下面的类解析一个非常大的字符串(整个文本小说)并将其分解为连续的 4 个字符的字符串,这些字符串存储为一个元组。然后可以根据计算为每个元组分配一个概率。我将其用作蒙特卡罗/遗传算法的一部分来训练程序仅基于语法(仅字符转换)来识别语言。
我想知道是否有更快的方法来做到这一点。查找任何给定的 4 字符元组的概率大约需要 400 毫秒。相关方法 _Probablity() 位于类的末尾。
这是与我的另一篇文章相关的计算密集型问题:计算函数的合理性的算法/蒙特卡洛方法
最终,我想将这些值存储在 4d 矩阵中。但鉴于字母表中有 26 个字母,这将是一项艰巨的任务。(26x26x26x26)。如果我只取小说的前 15000 个字符,那么性能会提高很多,但我的数据没有那么有用。
这是解析文本“源”的方法:
private List<Tuple<char, char, char, char>> _Parse(string src)
{
var _map = new List<Tuple<char, char, char, char>>();
for (int i = 0; i < src.Length - 3; i++)
{
int j = i + 1;
int k = i + 2;
int l = i + 3;
_map.Add
(new Tuple<char, char, char, char>(src[i], src[j], src[k], src[l]));
}
return _map;
}
这是 _Probability 方法:
private double _Probability(char x0, char x1, char x2, char x3)
{
var subset_x0 = map.Where(x => x.Item1 == x0);
var subset_x0_x1_following = subset_x0.Where(x => x.Item2 == x1);
var subset_x0_x2_following = subset_x0_x1_following.Where(x => x.Item3 == x2);
var subset_x0_x3_following = subset_x0_x2_following.Where(x => x.Item4 == x3);
int count_of_x0 = subset_x0.Count();
int count_of_x1_following = subset_x0_x1_following.Count();
int count_of_x2_following = subset_x0_x2_following.Count();
int count_of_x3_following = subset_x0_x3_following.Count();
decimal p1;
decimal p2;
decimal p3;
if (count_of_x0 <= 0 || count_of_x1_following <= 0 || count_of_x2_following <= 0 || count_of_x3_following <= 0)
{
p1 = e;
p2 = e;
p3 = e;
}
else
{
p1 = (decimal)count_of_x1_following / (decimal)count_of_x0;
p2 = (decimal)count_of_x2_following / (decimal)count_of_x1_following;
p3 = (decimal)count_of_x3_following / (decimal)count_of_x2_following;
p1 = (p1 * 100) + e;
p2 = (p2 * 100) + e;
p3 = (p3 * 100) + e;
}
//more calculations omitted
return _final;
}
}
编辑- 我正在提供更多细节来解决问题,
1)严格来说,到目前为止我只使用过英语,但确实必须考虑不同的字母表。目前我只希望程序识别英语,类似于本文中描述的内容:http ://www-stat.stanford.edu/~cgates/PERSI/papers/MCMCRev.pdf
2)我正在计算 n <= 4 的字符元组的概率。例如,如果我正在计算字符串“that”的总概率,我会将其分解为这些独立的元组并计算每个元组的概率首先单独:
[吨][小时]
[t][h][a]
[那]
[t][h] 的权重最大,然后是 [t][h][a],然后是 [t][h][a][t]。由于我不只是将 4 字符元组视为一个单元,因此我无法仅将文本中 [t][h][a][t] 的实例除以总数。接下来是 4 元组。
分配给每个 4 元组的值不能过拟合文本,因为偶然许多真正的英语单词可能永远不会出现在文本中,它们不应该得到不成比例的低分。强调一阶字符转换(2 元组)可以改善这个问题。移动到 3 元组,然后 4 元组只是细化了计算。
我想出了一个字典,它简单地计算元组在文本中出现的频率(类似于 Vilx 建议的),而不是重复相同的元组,这会浪费内存。这让我从每次查找约 400 毫秒到每次约 40 毫秒,这是一个相当大的改进。但是,我仍然需要研究其他一些建议。