/// <summary>
        /// Learns and extracts the meta features learned by the ensemble models on the provided indices
        /// </summary>
        /// <param name="observations"></param>
        /// <param name="targets"></param>
        /// <param name="indices"></param>
        /// <returns></returns>
        public F64Matrix LearnMetaFeatures(F64Matrix observations, double[] targets,
                                           int[] indices)
        {
            var numberOfClasses = targets.Distinct().Count();

            var cvRows           = indices.Length;
            var ensembleFeatures = m_learners.Length * numberOfClasses;
            var cvCols           = ensembleFeatures;

            if (m_includeOriginalFeaturesForMetaLearner)
            {
                cvCols = cvCols + observations.ColumnCount;
            }

            var cvPredictions    = new F64Matrix(cvRows, cvCols);
            var modelPredictions = new ProbabilityPrediction[cvRows];

            for (int i = 0; i < m_learners.Length; i++)
            {
                Trace.WriteLine("Training model: " + (i + 1));
                var learner = m_learners[i];
                m_crossValidation.CrossValidate(learner, observations, targets,
                                                indices, modelPredictions);

                for (int j = 0; j < modelPredictions.Length; j++)
                {
                    var probabilities = modelPredictions[j].Probabilities.Values.ToArray();
                    for (int k = 0; k < probabilities.Length; k++)
                    {
                        cvPredictions[j, i *numberOfClasses + k] = probabilities[k];
                    }
                }
            }

            if (m_includeOriginalFeaturesForMetaLearner)
            {
                for (int i = 0; i < cvRows; i++)
                {
                    for (int j = 0; j < observations.ColumnCount; j++)
                    {
                        var value = cvPredictions[i, j + ensembleFeatures];
                        cvPredictions[i, j + ensembleFeatures] = observations[indices[i], j];
                    }
                }
            }

            return(cvPredictions);
        }
        /// <summary>
        /// Learns and extracts the meta features learned by the ensemble models on the provided indices
        /// </summary>
        /// <param name="observations"></param>
        /// <param name="targets"></param>
        /// <param name="indices"></param>
        /// <returns></returns>
        public ProbabilityPrediction[][] LearnMetaFeatures(F64Matrix observations, double[] targets, int[] indices)
        {
            var cvRows = indices.Length;
            var cvCols = m_learners.Length;

            var ensemblePredictions = new ProbabilityPrediction[cvCols][];

            for (int i = 0; i < m_learners.Length; i++)
            {
                Trace.WriteLine("Training model: " + (i + 1));
                var learner            = m_learners[i];
                var learnerPredictions = new ProbabilityPrediction[cvRows];
                m_crossValidation.CrossValidate(learner, observations, targets, indices, learnerPredictions);
                ensemblePredictions[i] = learnerPredictions;
            }

            return(ensemblePredictions);
        }
        /// <summary>
        /// Learns and extracts the meta features learned by the ensemble models on the provided indices
        /// </summary>
        /// <param name="observations"></param>
        /// <param name="targets"></param>
        /// <param name="indices"></param>
        /// <returns></returns>
        public F64Matrix LearnMetaFeatures(F64Matrix observations, double[] targets, int[] indices)
        {
            var cvRows = indices.Length;
            var cvCols = m_learners.Length;

            var cvPredictions    = new F64Matrix(cvRows, cvCols);
            var modelPredictions = new double[cvRows];

            for (int i = 0; i < m_learners.Length; i++)
            {
                Trace.WriteLine("Training model: " + (i + 1));
                var learner = m_learners[i];
                m_crossValidation.CrossValidate(learner, observations, targets, indices, modelPredictions);
                for (int j = 0; j < modelPredictions.Length; j++)
                {
                    cvPredictions[j, i] = modelPredictions[j];
                }
            }

            return(cvPredictions);
        }
        /// <summary>
        /// Learns and extracts the meta features learned by the ensemble models on the provided indices
        /// </summary>
        /// <param name="observations"></param>
        /// <param name="targets"></param>
        /// <param name="indices"></param>
        /// <returns></returns>
        public F64Matrix LearnMetaFeatures(F64Matrix observations, double[] targets,
                                           int[] indices)
        {
            var cvRows = indices.Length;
            var cvCols = m_learners.Length;

            if (m_includeOriginalFeaturesForMetaLearner)
            {
                cvCols = cvCols + observations.ColumnCount;
            }

            var cvPredictions    = new F64Matrix(cvRows, cvCols);
            var modelPredictions = new double[cvRows];

            for (int i = 0; i < m_learners.Length; i++)
            {
                Trace.WriteLine("Training model: " + (i + 1));

                var learner = m_learners[i];
                m_crossValidation.CrossValidate(learner, observations, targets,
                                                indices, modelPredictions);

                for (int j = 0; j < modelPredictions.Length; j++)
                {
                    cvPredictions[j, i] = modelPredictions[j];
                }
            }

            if (m_includeOriginalFeaturesForMetaLearner)
            {
                for (int i = 0; i < cvRows; i++)
                {
                    for (int j = 0; j < observations.ColumnCount; j++)
                    {
                        cvPredictions[i, j + m_learners.Length] = observations[indices[i], j];
                    }
                }
            }
            return(cvPredictions);
        }