【发布时间】:2011-11-20 00:20:54
【问题描述】:
下面的类解析一个非常大的字符串(整个文本小说)并将其分解为连续的 4 个字符的字符串,这些字符串存储为一个元组。然后可以根据计算为每个元组分配一个概率。我将其用作蒙特卡洛/遗传算法的一部分,以训练程序仅基于语法(仅字符转换)识别语言。
我想知道是否有更快的方法来做到这一点。查找任何给定的 4 字符元组的概率大约需要 400 毫秒。相关方法 _Probablity() 位于类的末尾。
这是与我的另一篇文章相关的计算密集型问题:Algorithm for computing the plausibility of a function / Monte Carlo Method
最终我想将这些值存储在 4d 矩阵中。但鉴于字母表中有 26 个字母,这将是一项艰巨的任务。 (26x26x26x26)。如果我只取小说的前 15000 个字符,那么性能会提高很多,但我的数据没有那么有用。
这里是解析文本'source'的方法:
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
[t][h]
[t][h][a]
[t][h][a][t]
[t][h] 被赋予最大权重,然后是 [t][h][a],然后是 [t][h][a][t]。由于我不只是将 4 字符元组视为一个单元,因此我无法将文本中 [t][h][a][t] 的实例除以总数。接下来是 4 元组。
分配给每个 4 元组的值不能过拟合文本,因为偶然许多真正的英语单词可能永远不会出现在文本中,它们不应该得到不成比例的低分。强调一阶字符转换(2 元组)可以改善这个问题。移动到 3 元组,然后 4 元组只是细化了计算。
我想出了一个字典,它简单地计算元组在文本中出现的频率(类似于 Vilx 建议的),而不是重复相同的元组,这会浪费内存。这让我从每次查找约 400 毫秒到每次约 40 毫秒,这是一个相当大的改进。但是,我仍然需要研究其他一些建议。
【问题讨论】:
-
26^4 还不错。只有456,976。即使您将每个计数存储为 64 位数量,它仍然只有 3.5MB。对于今天的计算机来说几乎没有。你试过这种方法吗?
-
嗯,没错,但我遇到的主要障碍是,计算矩阵中的每个单元格并为其赋值大约需要 400 毫秒。因此,如果要分配 456,976 个值,那大约是 50 小时。我觉得对吗?我可以将 400 毫秒降低到大约 1 毫秒,但我只看一个小得多的样本,比如小说的前 15,000 个字符。
-
我不知道所需的计算,但你不能只看一遍文本,逐个字符,递增每个字符上的相应单元格吗?然后在每个单元格中,您都有该特定 4 字符组合的计数。然后,您将每个单元格除以 4 字符组合的总数(始终为
total_number_of_chars_in_text - 3)。您甚至可以避免预先进行除法,并在每次需要特定组合的概率时进行除法。 -
你说:“但是鉴于字母表中有 26 个字母......”。你必须小心那里。到那时,您几乎可以确定您的文本是英文 =)
-
+1。 26 仅适用于英文文本。并且你应该小心避免使用标点符号、空格、换行符等。
标签: c# artificial-intelligence nlp tuples montecarlo