private DecisionNode <TObj> trainID3Core(IEnumerable <Predicate <TObj> > patterns, ClassifiedSample <TObj> sample, IInformativityIndex <TObj> informativity) { if (!sample.Any()) { throw new MLException("Empty sample"); } var cls = sample.First().Value; if (sample.All(kvp => kvp.Value.Equals(cls))) { return(new LeafNode <TObj>(cls)); } var pattern = informativity.Max(patterns, sample); var negSample = new ClassifiedSample <TObj>(); var posSample = new ClassifiedSample <TObj>(); foreach (var pData in sample) { if (pattern(pData.Key)) { posSample.Add(pData.Key, pData.Value); } else { negSample.Add(pData.Key, pData.Value); } } if (!negSample.Any() || !posSample.Any()) { var majorClass = sample.GroupBy(pd => pd.Value) .Select(g => new KeyValuePair <Class, int>(g.Key, g.Count())) .OrderByDescending(c => c.Value) .First(); return(new LeafNode <TObj>(majorClass.Key)); } var node = new InnerNode <TObj>(pattern); var negNode = trainID3Core(patterns, negSample, informativity); var posNode = trainID3Core(patterns, posSample, informativity); node.SetNegativeNode(negNode); node.SetPositiveNode(posNode); return(node); }