public void RenderNode(Graphics graphics, GridCoordinate coordinate, DecisionTree.DecisionNode node)
            {
                var location = GetBitmapLocation(coordinate);

                graphics.DrawRectangle(Pens.Black, location.X, location.Y, ItemSize.Width, ItemSize.Height - 100);

                var font = new Font("Arial", 9);

                var message = node.IsLeaf
                    ? node.Class
                    : node.Children.First().Attribute + Environment.NewLine + "(" + node.Class + ")";

                var size       = graphics.MeasureString(message, font);
                var textWidth  = size.Width;
                var textHeight = size.Height;

                var stringLocationX = ((location.X + location.X + ItemSize.Width) / (float)2) - (textWidth / 2);
                var stringLocationY = ((location.Y + location.Y + ItemSize.Height - 100) / (float)2) - (textHeight / 2);

                graphics.DrawString(message, font, Brushes.Black, stringLocationX, stringLocationY);
            }
        private Dictionary <DecisionTree.DecisionNode, GridCoordinate> GetCoordinates(DecisionTree.DecisionNode root)
        {
            Dictionary <DecisionTree.DecisionNode, GridCoordinate> points =
                new Dictionary <DecisionTree.DecisionNode, GridCoordinate>();
            var leavesNodes = new List <DecisionTree.DecisionNode>();

            DecisionTree.LoadLeaves(root, leavesNodes);


            Func <DecisionTree.DecisionNode, GridCoordinate?> getPointFromChildren = node =>
            {
                if (node.Children == null || !node.Children.Any())
                {
                    return(null);
                }
                var xValue = (int)node.Children.Average(item =>
                {
                    var point = points[item];
                    return(point.Column);
                });

                return(new GridCoordinate {
                    Column = xValue, Row = node.Depth
                });
            };


            var nextColumnIndex = 0;
            var nodesToProcess  = leavesNodes;

            while (nodesToProcess.Count > 0)
            {
                var listNewNodesToProcess = new List <DecisionTree.DecisionNode>();
                foreach (var node in nodesToProcess)
                {
                    if (points.ContainsKey(node))
                    {
                        continue;
                    }
                    if (node.IsLeaf)
                    {
                        points.Add(node, new GridCoordinate {
                            Column = nextColumnIndex, Row = node.Depth
                        });
                        nextColumnIndex = nextColumnIndex + 2;
                    }
                    else
                    {
                        var childrenResolved = node.Children.All(child => points.ContainsKey(child));
                        if (!childrenResolved)
                        {
                            continue;
                        }
                        var point = getPointFromChildren(node);
                        if (point.HasValue)
                        {
                            points.Add(node, point.Value);
                        }
                    }

                    if (node.Parent != null)
                    {
                        listNewNodesToProcess.Add(node.Parent);
                    }
                }

                nodesToProcess = listNewNodesToProcess;
            }


            return(points);
        }
        private void BuildConditionalNodes(IList <int> rows, IList <int> attributesIndexes,
                                           DecisionTree.DecisionNode parentNode)
        {
            var stack = new Stack <Iteration>();

            stack.Push(new Iteration
            {
                Attributes = attributesIndexes,
                ParentNode = parentNode,
                Rows       = rows,
            });

            Iteration currentIteration = stack.Pop();

            while (currentIteration != null)
            {
                var attributesList = currentIteration.Attributes.ToList();
                if (attributesList.Count == 0)
                {
                    currentIteration.ParentNode.Statistics = ComputeStatistics(currentIteration.Rows);
                    currentIteration.ParentNode.Class      = _data.ClassesValue[(int)currentIteration.ParentNode.Statistics.MostFrequentClass];
                    currentIteration = stack.Count > 0 ? stack.Pop() : null;
                    continue;
                }


                var result     = ComputeBestGain(currentIteration.Rows.ToArray(), currentIteration.Attributes);
                var statistics = result.Item3;

                currentIteration.ParentNode.Statistics = statistics;
                currentIteration.ParentNode.Class      = _data.ClassesValue[(int)statistics.MostFrequentClass];
                if (statistics.SameClass || (currentIteration.ParentNode.Depth == _options.MaxTreeDepth && _options.MaxTreeDepth > 0))
                {
                    currentIteration = stack.Count > 0 ? stack.Pop() : null;
                    continue;
                }
                var attributeResult = result.Item2;

                var first    = true;
                var children = new List <DecisionTree.DecisionNode>();

                attributesList.Remove(attributeResult.AttributeIndex);
                if (attributeResult.InvalidAttributes.Any())
                {
                    foreach (var item in attributeResult.InvalidAttributes)
                    {
                        attributesList.Remove(item);
                    }
                }

                var subsets = attributeResult.Subsets.Value.ToList();
                attributeResult.Subsets = null;

                foreach (var subset in subsets)
                {
                    var node = new DecisionTree.DecisionNode
                    {
                        Condition = attributeResult.IsNumeric
                            ? first
                                ? DecisionTree.PredicateCondition.LessThanOrEqual
                                : DecisionTree.PredicateCondition.GreaterThan
                            : DecisionTree.PredicateCondition.Equal,
                        ThreshHold = subset.Value,
                        Attribute  = _data.Attributes[attributeResult.AttributeIndex],
                        Depth      = currentIteration.ParentNode.Depth + 1,
                        Parent     = currentIteration.ParentNode
                    };

                    stack.Push(new Iteration
                    {
                        Rows       = subset.Rows,
                        Attributes = attributesList,
                        ParentNode = node,
                    });
                    first = false;

                    children.Add(node);
                }
                currentIteration.ParentNode.Children = children.ToArray();
                currentIteration = stack.Count > 0 ? stack.Pop() : null;
            }
        }
        private void BuildConditionalNodesRecursive(int[] rows, IList <int> attributesIndexes,
                                                    DecisionTree.DecisionNode parentNode)
        {
            var attributesList = attributesIndexes.ToList();

            if (attributesList.Count == 0)
            {
                parentNode.Statistics = ComputeStatistics(rows);
                parentNode.Class      = _data.ClassesValue[(int)parentNode.Statistics.MostFrequentClass];
                return;
            }

            var result = ComputeBestGain(rows, attributesIndexes);

            var statistics = result.Item3;

            parentNode.Statistics = statistics;
            parentNode.Class      = _data.ClassesValue[(int)statistics.MostFrequentClass];

            if (statistics.SameClass || (parentNode.Depth == _options.MaxTreeDepth && _options.MaxTreeDepth > 0))
            {
                return;
            }

            var attributeResult = result.Item2;

            var first    = true;
            var children = new List <DecisionTree.DecisionNode>();

            attributesList.Remove(attributeResult.AttributeIndex);
            if (attributeResult.InvalidAttributes.Any())
            {
                foreach (var item in attributeResult.InvalidAttributes)
                {
                    attributesList.Remove(item);
                }
            }

            var subsets = attributeResult.Subsets.Value;

            attributeResult.Subsets = null;

            foreach (var subset in subsets)
            {
                if (subset.Rows.Count < _options.MinItemsOnNode)
                {
                    continue;
                }
                var node = new DecisionTree.DecisionNode
                {
                    Condition = attributeResult.IsNumeric
                        ? first
                            ? DecisionTree.PredicateCondition.LessThanOrEqual
                            : DecisionTree.PredicateCondition.GreaterThan
                        : DecisionTree.PredicateCondition.Equal,
                    ThreshHold = subset.Value,
                    Attribute  = _data.Attributes[attributeResult.AttributeIndex],
                    Depth      = parentNode.Depth + 1,
                    Parent     = parentNode
                };

                BuildConditionalNodesRecursive(subset.Rows.ToArray(), attributesList, node);
                first = false;

                children.Add(node);
            }
            parentNode.Children = children.ToArray();
        }