public Attribute SelectBestAtr(List <Attribute> attributeList)
        {
            List <double> atrGainRatio = new List <double>();

            for (int i = 0; i < attributeList.Count; i++)
            {
                atrGainRatio.Add(ID3Helper.CalculateGain(AttributeInformation(DataProcessing(attributeList[i])), SetEntropy) / SplitInfo(DataProcessing(attributeList[i])));
            }
            int maxGainRatio = atrGainRatio.
                               Select((value, index) => new { Value = value, Index = index }).
                               Aggregate((a, b) => (a.Value > b.Value) ? a : b).
                               Index;

            return(attributeList[maxGainRatio]);
        }
        public double SplitInfo(List <List <int> > atrData)
        {
            double splitInfo = 0;

            foreach (List <int> valList in atrData)
            {
                splitInfo += ID3Helper.CalculateSplitInfo(valList.Sum(), DecisionValues.Values.Count);
            }
            if (splitInfo != 0)
            {
                return(splitInfo);
            }
            else
            {
                return(1.0);
            }
        }
        public TreeNode ID3Algorithm(List <Attribute> attributeList, Attribute decisionValues)
        {
            TreeNode      tn = new TreeNode();
            List <object> dv = decisionValues.Values;

            if (attributeList.Count == 0)
            {
                tn.decription = "Failure";
                return(tn);
            }

            if (dv.Distinct().Count().Equals(1))
            {
                tn.decription = dv[0];
                return(tn);
            }

            #region ATTRIBUTE SELECTION, SUBSET CREATION, RECURRENCE
            DecisionValues = decisionValues;
            SetEntropy     = ID3Helper.InitSetEntropy(decisionValues);
            Attribute     selectedAtr            = SelectBestAtr(attributeList);
            List <object> distinctSelectedAtrVal = selectedAtr.Values.Distinct().OrderBy(x => x).ToList();
            attributeList.Remove(selectedAtr);

            for (int dObj = 0; dObj < distinctSelectedAtrVal.Count(); dObj++)
            {
                List <Attribute> subsetAtrLs = new List <Attribute>();
                for (int i = 0; i < attributeList.Count; i++)
                {
                    List <object> subsetVal = new List <object>();
                    for (int j = 0; j < attributeList[i].Values.Count; j++)
                    {
                        if (selectedAtr.Values[j].Equals(distinctSelectedAtrVal[dObj]))
                        {
                            subsetVal.Add(attributeList[i].Values[j]);
                        }
                    }
                    subsetAtrLs.Add(new Attribute(attributeList[i].Name, subsetVal));
                }

                Attribute     subsetDec    = new Attribute();
                List <object> subsetDecVal = new List <object>();
                for (int j = 0; j < decisionValues.Values.Count; j++)
                {
                    if (selectedAtr.Values[j].Equals(distinctSelectedAtrVal[dObj]))
                    {
                        subsetDecVal.Add(decisionValues.Values[j]);
                    }
                }
                subsetDec.Name   = decisionValues.Name;
                subsetDec.Values = subsetDecVal;

                tn.decription = selectedAtr.Name.ToString();
                //tn.child.Add(ID3Algorithm(subsetAtrLs, subsetDec));
                TreeNode childNode = ID3Algorithm(subsetAtrLs, subsetDec);
                childNode.parentDescription = distinctSelectedAtrVal[dObj].ToString();
                tn.child.Add(childNode);
            }
            #endregion
            return(tn);
        }
        public double AttributeInformation(List <List <int> > atrData)
        {
            double atrInformation = 0;

            foreach (List <int> valList in atrData)
            {
                atrInformation += ((double)valList.Sum() / DecisionValues.Values.Count) * ID3Helper.CalculateEntropy(valList);
            }
            return(atrInformation);
        }