protected double[] LearnerHistoryToWeights(PipelinePattern[] history, bool isMaximizingMetric)
        {
            int numLearners = AvailableLearners.Length;

            double[] weights = new double[numLearners];
            int[]    counts  = new int[numLearners];
            Dictionary <string, int> labelToIndex = new Dictionary <string, int>();
            double maxWeight = history.Length > 0 ? history.Max(w => w.PerformanceSummary.MetricValue) : 0d;

            // Map categorical values to their index
            for (int j = 0; j < numLearners; j++)
            {
                labelToIndex[AvailableLearners[j].LearnerName] = j;
            }

            // Add mass according to performance
            foreach (var pipeline in history)
            {
                if (AvailableLearners.All(l => l.LearnerName != pipeline.Learner.LearnerName))
                {
                    continue;
                }
                weights[labelToIndex[pipeline.Learner.LearnerName]] +=
                    AutoMlUtils.ProcessWeight(pipeline.PerformanceSummary.MetricValue,
                                              maxWeight, isMaximizingMetric);
                counts[labelToIndex[pipeline.Learner.LearnerName]]++;
            }

            // Take average mass for each learner
            for (int i = 0; i < weights.Length; i++)
            {
                weights[i] /= counts[i] > 0 ? counts[i] : 1;
            }

            // If any learner has not been seen, default its average to 1.0
            // to encourage exploration of untried algorithms.
            for (int i = 0; i < weights.Length; i++)
            {
                weights[i] += counts[i] == 0 ? 1 : 0;
            }

            // Normalize weights to sum to one and return
            return(SweeperProbabilityUtils.Normalize(weights));
        }