private OutputProperties InitOutputProperties(IQueryable <T> data)
        {
            var arg = Expression.Parameter(typeof(T), "x");

            var selectArgs = Expression.Parameter(typeof(IGrouping <,>).MakeGenericType(outputFeature.DataType, typeof(T)), "x");
            var selectCtor = Expression.New(typeof(GroupInfo));
            //int Count<TSource>(this IEnumerable<TSource> source);
            var countMethod = typeof(Enumerable).GetMethods().First(x => x.Name == "Count").MakeGenericMethod(typeof(T));

            var selectMemberInit = Expression.MemberInit(selectCtor,
                                                         Expression.Bind(typeof(GroupInfo).GetProperty("Output"), Expression.Convert(Expression.Property(selectArgs, "Key"), typeof(object))),
                                                         Expression.Bind(typeof(GroupInfo).GetProperty("Count"), Expression.Call(countMethod, selectArgs))
                                                         );
            var selectLambdaExpression = Expression.Lambda(selectMemberInit, selectArgs);


            var groupedData = IQueryableHelper.GroupBy(data, outputFeature.Selector, typeof(T), outputFeature.DataType);
            var groups      = (IQueryableHelper.Select(groupedData, selectLambdaExpression, typeof(IGrouping <,>).MakeGenericType(outputFeature.DataType, typeof(T)),
                                                       typeof(GroupInfo)) as IQueryable <GroupInfo>).ToArray();

            return(new DecisionTreeOutputProperties()
            {
                DataCount = groups.Sum(x => x.Count),
                OutputDistribution = groups.ToDictionary(x => x.Output, x => x.Count),
            });
        }
        private IQueryable <InputOutputPair> BranchContiniousData(Feature feature, IQueryable <T> data)
        {
            var orderedData = IQueryableHelper.OrderBy(data, feature.Selector, typeof(T), feature.DataType);

            var arg              = Expression.Parameter(typeof(T), "x");
            var ctor             = Expression.New(typeof(InputOutputPair));
            var inputExpression  = ExpressionHelper.ReplaceLambdaParameter(feature.Selector as LambdaExpression, arg);
            var outputExpression = ExpressionHelper.ReplaceLambdaParameter(outputFeature.Selector as LambdaExpression, arg);

            var selectMemberInit = Expression.MemberInit(ctor,
                                                         Expression.Bind(typeof(InputOutputPair).GetProperty("Input"), Expression.Convert(inputExpression, typeof(object))),
                                                         Expression.Bind(typeof(InputOutputPair).GetProperty("Output"), Expression.Convert(outputExpression, typeof(object)))
                                                         );
            var selectLambdaExpression = Expression.Lambda(selectMemberInit, arg);
            var orderedInputOutput     = IQueryableHelper.Select(orderedData, selectLambdaExpression, typeof(T), typeof(InputOutputPair)) as IQueryable <InputOutputPair>;

            return(orderedInputOutput);
        }
        private GroupInfo[] GroupFeatureWithOutput(Feature feature, IQueryable <T> data)
        {
            var arg         = Expression.Parameter(typeof(T), "x");
            var groupByType = typeof(GroupBy <,>).MakeGenericType(feature.DataType, outputFeature.DataType);
            var ctor        = Expression.New(groupByType);

            var inputExp = new ReplaceExpressionVisitor((feature.Selector as LambdaExpression).Parameters[0], arg)
                           .Visit((feature.Selector as LambdaExpression).Body);
            var outputExp = new ReplaceExpressionVisitor((outputFeature.Selector as LambdaExpression).Parameters[0], arg)
                            .Visit((outputFeature.Selector as LambdaExpression).Body);

            var bindExpInput  = Expression.Bind(groupByType.GetProperty("Input"), inputExp);//TODO: FIX THIS
            var bindExpOutput = Expression.Bind(groupByType.GetProperty("Output"), outputExp);

            var groupByExpression = Expression.MemberInit(ctor, new MemberBinding[] { bindExpInput, bindExpOutput });
            var lambdaExpression  = Expression.Lambda(groupByExpression, arg);
            var groups            = IQueryableHelper.GroupBy(data, lambdaExpression, typeof(T), groupByType);

            var selectArgs = Expression.Parameter(typeof(IGrouping <,>).MakeGenericType(groupByType, typeof(T)), "x");
            var selectCtor = Expression.New(typeof(GroupInfo));

            //int Count<TSource>(this IEnumerable<TSource> source);
            var countMethod = typeof(Enumerable).GetMethods().First(x => x.Name == "Count").MakeGenericMethod(typeof(T));

            var selectMemberInit = Expression.MemberInit(selectCtor,
                                                         Expression.Bind(typeof(GroupInfo).GetProperty("Input"), Expression.Convert(Expression.Property(Expression.Property(selectArgs, "Key"), "Input"), typeof(object))),
                                                         Expression.Bind(typeof(GroupInfo).GetProperty("Output"), Expression.Convert(Expression.Property(Expression.Property(selectArgs, "Key"), "Output"), typeof(object))),
                                                         Expression.Bind(typeof(GroupInfo).GetProperty("Count"), Expression.Call(countMethod, selectArgs))
                                                         );
            var selectLambdaExpression = Expression.Lambda(selectMemberInit, selectArgs);

            var selectedGroups = IQueryableHelper.Select(groups, selectLambdaExpression, typeof(IGrouping <,>)
                                                         .MakeGenericType(groupByType, typeof(T)), typeof(GroupInfo)) as IQueryable <GroupInfo>;

            return(selectedGroups.ToArray());
            //var groups = this.GetType().GetMethod("GenericGroup")
            //    .MakeGenericMethod(feature.DataType, OutputFeature.DataType)
            //    .Invoke(this, new object[] { data, groupByExpression, arg }) as GroupInfo[];
        }