protected virtual IDecisionTreeNode BuildDecisionNode(
            IDataFrame dataFrame,
            string dependentFeatureName,
            IDecisionTreeModelBuilderParams additionalParams,
            IAlredyUsedAttributesInfo alreadyUsedAttributesInfo,
            int treeDepth,
            bool isFirstSplit = false)
        {
            if (dataFrame.GetColumnVector <object>(dependentFeatureName).DataItems.Distinct().Count() == 1 || MaximalTreeDepthHasBeenReached(additionalParams, treeDepth))
            {
                return(BuildLeaf(dataFrame, dependentFeatureName));
            }

            // TODO: later on add additional params indicating which features were already used
            ISplittingResult splitResult = BestSplitSelector.SelectBestSplit(
                dataFrame,
                dependentFeatureName,
                SplitQualityChecker,
                alreadyUsedAttributesInfo);

            if (SplitIsEmpty(splitResult))
            {
                return(BuildLeaf(dataFrame, dependentFeatureName));
            }

            if (additionalParams.UsePrunningHeuristicDuringTreeBuild && this.StatisticalSignificanceChecker != null)
            {
                var isSplitSignificant = StatisticalSignificanceChecker.IsSplitStatisticallySignificant(
                    dataFrame,
                    splitResult,
                    dependentFeatureName);
                if (!isSplitSignificant)
                {
                    return(BuildLeaf(dataFrame, dependentFeatureName));
                }
            }

            var children = new ConcurrentDictionary <IDecisionTreeLink, IDecisionTreeNode>();

            if (isFirstSplit)
            {
                Parallel.ForEach(
                    splitResult.SplittedDataSets,
                    splitData =>
                {
                    this.AddChildFromSplit(dependentFeatureName, additionalParams, splitData, children, alreadyUsedAttributesInfo, treeDepth + 1);
                });
            }
            else
            {
                foreach (var splitData in splitResult.SplittedDataSets)
                {
                    this.AddChildFromSplit(dependentFeatureName, additionalParams, splitData, children, alreadyUsedAttributesInfo, treeDepth + 1);
                }
            }
            return(BuildConcreteDecisionTreeNode(splitResult, children));
        }
        protected virtual void AddLeafFromSplit(
            string dependentFeatureName,
            IDecisionTreeModelBuilderParams additionalParams,
            ISplittedData splitData,
            IDataFrame baseData,
            ConcurrentDictionary <IDecisionTreeLink, IDecisionTreeNode> children)
        {
            var leafNode = BuildLeaf(baseData, dependentFeatureName);
            var link     = splitData.SplitLink;

            children.TryAdd(link, leafNode);
        }
        protected virtual void AddChildFromSplit(
            string dependentFeatureName,
            IDecisionTreeModelBuilderParams additionalParams,
            ISplittedData splitData,
            ConcurrentDictionary <IDecisionTreeLink, IDecisionTreeNode> children,
            IAlredyUsedAttributesInfo alreadyUsedAttributesInfo,
            int treeDepth)
        {
            var decisionTreeNode = BuildDecisionNode(
                splitData.SplittedDataFrame,
                dependentFeatureName,
                additionalParams,
                alreadyUsedAttributesInfo,
                treeDepth);
            var link = splitData.SplitLink;

            children.TryAdd(link, decisionTreeNode);
        }
 protected virtual void AddChildFromSplit(
     string dependentFeatureName, 
     IDecisionTreeModelBuilderParams additionalParams, 
     ISplittedData splitData, 
     ConcurrentDictionary<IDecisionTreeLink, IDecisionTreeNode> children, 
     IAlredyUsedAttributesInfo alreadyUsedAttributesInfo,
     int treeDepth)
 {
     var decisionTreeNode = BuildDecisionNode(
         splitData.SplittedDataFrame,
         dependentFeatureName,
         additionalParams,
         alreadyUsedAttributesInfo,
         treeDepth);
     var link = splitData.SplitLink;
     children.TryAdd(link, decisionTreeNode);
 }
 private static bool MaximalTreeDepthHasBeenReached(IDecisionTreeModelBuilderParams additionalParams, int treeDepth)
 {
     return additionalParams.MaximalTreeDepth.HasValue && treeDepth >= additionalParams.MaximalTreeDepth;
 }
        protected virtual IDecisionTreeNode BuildDecisionNode(
            IDataFrame dataFrame, 
            string dependentFeatureName,
            IDecisionTreeModelBuilderParams additionalParams,
            IAlredyUsedAttributesInfo alreadyUsedAttributesInfo, 
            int treeDepth,
            bool isFirstSplit = false)
        {
            if (dataFrame.GetColumnVector<object>(dependentFeatureName).DataItems.Distinct().Count() == 1 || MaximalTreeDepthHasBeenReached(additionalParams, treeDepth))
            {
                return BuildLeaf(dataFrame, dependentFeatureName);
            }

            // TODO: later on add additional params indicating which features were already used
            ISplittingResult splitResult = BestSplitSelector.SelectBestSplit(
                dataFrame,
                dependentFeatureName,
                SplitQualityChecker,
                alreadyUsedAttributesInfo);
            if (SplitIsEmpty(splitResult))
            {
                return BuildLeaf(dataFrame, dependentFeatureName);
            }

            if (additionalParams.UsePrunningHeuristicDuringTreeBuild && this.StatisticalSignificanceChecker != null)
            {
                var isSplitSignificant = StatisticalSignificanceChecker.IsSplitStatisticallySignificant(
                    dataFrame,
                    splitResult,
                    dependentFeatureName);
                if (!isSplitSignificant)
                {
                    return BuildLeaf(dataFrame, dependentFeatureName);
                }
            }

            var children = new ConcurrentDictionary<IDecisionTreeLink, IDecisionTreeNode>();
            if (isFirstSplit)
            {
                Parallel.ForEach(
                    splitResult.SplittedDataSets,
                    splitData =>
                    {
                        this.AddChildFromSplit(dependentFeatureName, additionalParams, splitData, children, alreadyUsedAttributesInfo, treeDepth + 1);
                    });
            }
            else
            {
                foreach (var splitData in splitResult.SplittedDataSets)
                {
                    this.AddChildFromSplit(dependentFeatureName, additionalParams, splitData, children, alreadyUsedAttributesInfo, treeDepth + 1);
                }
            }
            return BuildConcreteDecisionTreeNode(splitResult, children);
        }
 protected virtual void AddLeafFromSplit(
     string dependentFeatureName, 
     IDecisionTreeModelBuilderParams additionalParams, 
     ISplittedData splitData, 
     IDataFrame baseData, 
     ConcurrentDictionary<IDecisionTreeLink, IDecisionTreeNode> children)
 {
     var leafNode = BuildLeaf(baseData, dependentFeatureName);
     var link = splitData.SplitLink;
     children.TryAdd(link, leafNode);
 }
 private static bool MaximalTreeDepthHasBeenReached(IDecisionTreeModelBuilderParams additionalParams, int treeDepth)
 {
     return(additionalParams.MaximalTreeDepth.HasValue && treeDepth >= additionalParams.MaximalTreeDepth);
 }