C# 正在寻找一种优化此算法的方法来解析非常大的字符串

C# 正在寻找一种优化此算法的方法来解析非常大的字符串,c#,artificial-intelligence,nlp,tuples,montecarlo,C#,Artificial Intelligence,Nlp,Tuples,Montecarlo,下面的类解析一个非常大的字符串(一整本小说文本),并将其分解为连续的4个字符的字符串,这些字符串存储为元组。然后,可以根据计算为每个元组分配一个概率。我将此作为蒙特卡罗/遗传算法的一部分,训练程序仅基于语法识别语言(仅基于字符转换) 我想知道是否有一种更快的方法来做到这一点。查找任何给定的4个字符元组的概率大约需要400毫秒。相关的方法_probability()位于类的末尾 这是一个与我的另一篇文章相关的计算密集型问题: 最后,我想将这些值存储在4d矩阵中。但考虑到字母表中有26个字母,这将是

下面的类解析一个非常大的字符串(一整本小说文本),并将其分解为连续的4个字符的字符串,这些字符串存储为元组。然后,可以根据计算为每个元组分配一个概率。我将此作为蒙特卡罗/遗传算法的一部分,训练程序仅基于语法识别语言(仅基于字符转换)

我想知道是否有一种更快的方法来做到这一点。查找任何给定的4个字符元组的概率大约需要400毫秒。相关的方法_probability()位于类的末尾

这是一个与我的另一篇文章相关的计算密集型问题:

最后,我想将这些值存储在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; 
    }
private List\u解析(字符串src)
{
var_map=新列表();
对于(int i=0;i
这里是_概率法:

    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; 
    }
}
私有双概率(char x0,char x1,char x2,char x3)
{
var子集_x0=映射,其中(x=>x.Item1==x0);
var subset_x0_x1_following=subset_x0.式中(x=>x.Item2==x1);
var subset_x0_x2_following=subset_x0_x1_following.式中(x=>x.Item3==x2);
var subset\u x0\u x3\u following=subset\u x0\u x2\u following.其中(x=>x.Item4==x3);
int count_of_x0=子集_x0.count();
int count_of_x1_following=子集_x0_x1_following.count();
int count_of_x2_following=子集_x0_x2_following.count();
int count_of_x3_following=子集_x0_x3_following.count();
十进制p1;
小数点p2;
小数点p3;

如果(count_of_x0,我建议更改数据结构,使其更快


我认为
字典
会更有效率,因为在计算时,您将访问每个“级别”(Item1…Item4),并将结果缓存在最里面的
字典
中,因此下次您根本不需要计算。

我建议更改数据结构以加快计算速度


我认为
字典
会更有效率,因为您将访问每个“级别”(Item1…Item4)在计算…时,您会将结果缓存在最内层的
字典中,这样下次您就不必计算了。

在yoiu概率方法中,您将对映射进行8次迭代。每个Where都会迭代整个列表,计数也会如此。添加一个.ToList()作为结束(可能)加快速度。也就是说,我认为你的主要问题是,你选择用来存储数据的结构不适合概率方法。你可以创建一个一次性版本,其中存储数据的结构计算插入时的暂定分布。这样,当你完成插入时(这不应该减慢太多)您已经完成了,或者您可以按照下面的代码在需要时对概率进行廉价的计算

顺便说一句,你可能需要考虑puntiation和空格。句子的第一个字母/单词和单词的第一个字母通过将puntiation字符和空格作为你的分布的一部分来清楚地指示给定文本是用什么语言写的。你包括了样本数据的这些特征。我们做了几年前,我们这样做表明,只使用三个字符几乎是一样精确的(我们的测试数据中有三个字符,没有失败,并且假设存在一些奇怪的文本,缺少信息会产生不正确的结果),这与使用更多字符一样精确(我们测试到7)但是三个字母的速度使这成为最好的例子

编辑

这里有一个例子,我认为我应该如何在C中实现它#


在yoiu概率方法中,您要迭代映射8次。每个Where都会迭代整个列表,计数也是如此。在末尾添加一个.ToList()可能会加快速度。也就是说,我认为你的主要问题是,你选择用来存储数据的结构不适合概率方法。你可以创建一个一次性版本,其中存储数据的结构计算插入时的暂定分布。这样,当你完成插入时(这不应该减慢太多)您已经完成了,或者您可以按照下面的代码在需要时对概率进行廉价的计算

顺便说一句,你可能需要考虑puntiation和空格。句子的第一个字母/单词和单词的第一个字母通过将puntiation字符和空格作为你的分布的一部分来清楚地指示给定文本是用什么语言写的。你包括了样本数据的这些特征。我们做了几年前,我们这样做表明,只使用三个字符几乎是一样精确的(我们的测试数据中有三个字符,没有失败,并且假设存在一些奇怪的文本,缺少信息会产生不正确的结果),这与使用更多字符一样精确(我们测试到7)但是三个字母的速度使这成为最好的例子

编辑

这里有一个例子,我认为我应该如何在C中实现它#


好吧,我没有时间去弄清楚细节,但这确实需要时间

  • 神经分类器网络(只需从架子上取下任何
    class TextParser{
            private Node Parse(string src){
                var top = new Node(null);
    
                for (int i = 0; i < src.Length - 3; i++){
                    var first = src[i];
                    var second = src[i+1];
                    var third = src[i+2];
                    var fourth = src[i+3];
    
                    var firstLevelNode = top.AddChild(first);
                    var secondLevelNode = firstLevelNode.AddChild(second);
                    var thirdLevelNode = secondLevelNode.AddChild(third);
                    thirdLevelNode.AddChild(fourth);
                }
    
                return top;
            }
        }
    
        public class Node{
            private readonly Node _parent;
            private readonly Dictionary<char,Node> _children 
                             = new Dictionary<char, Node>();
            private int _count;
    
            public Node(Node parent){
                _parent = parent;
            }
    
            public Node AddChild(char value){
                if (!_children.ContainsKey(value))
                {
                    _children.Add(value, new Node(this));
                }
                var levelNode = _children[value];
                levelNode._count++;
                return levelNode;
            }
            public decimal Probability(string substring){
                var node = this;
                foreach (var c in substring){
                    if(!node.Contains(c))
                        return 0m;
                    node = node[c];
                }
                return ((decimal) node._count)/node._parent._children.Count;
            }
    
            public Node this[char value]{
                get { return _children[value]; }
            }
            private bool Contains(char c){
                return _children.ContainsKey(c);
            }
        }
    
    var top = Parse(src);
    top.Probability("test");
    
    SortedDictionary <int,int> count_of_single_letters; // key = single character
    SortedDictionary <int,int> count_of_double_letters; // key = char1 + char2 * 32
    SortedDictionary <int,int> count_of_triple_letters; // key = char1 + char2 * 32 + char3 * 32 * 32
    SortedDictionary <int,int> count_of_quad_letters;   // key = char1 + char2 * 32 + char3 * 32 * 32 + char4 * 32 * 32 * 32