class_docstr: This class is responsible for analyzing the results and outputting various types of analysis to the results folder.
class_docstr_tok: ["This","class","is","responsible","for","analyzing","the","results","and","outputting","various","types","of","analysis","to","the","results","folder","."]
code: def computeParameterResultValues(
      self,
      results,
      parameter,
      valueKey="loss",
      cutoff=1.0,
      numBuckets=None,
      bucket_reduction="mean",
  ):
      mergedResults = {}
      for result in results:
          if (
              isinstance(result[parameter.root[5:]], int)
              or isinstance(result[parameter.root[5:]], float)
              or isinstance(result[parameter.root[5:]], bool)
          ) and result[valueKey] is not None:
              value = result[parameter.root[5:]]
              loss = result[valueKey]
              key = str(roundPrecision(value, 3))
              if key in mergedResults:
                  mergedResults[key].append(loss)
              else:
                  mergedResults[key] = [loss]
  
      pairs = sorted(mergedResults.items(), key=lambda v: float(v[0]))
      values = [float(v[0]) for v in pairs]
  
      losses = []
      if bucket_reduction == "mean":
          losses = [numpy.mean(v[1]) for v in pairs]
      elif bucket_reduction == "median":
          losses = [numpy.median(v[1]) for v in pairs]
      elif bucket_reduction == "min":
          losses = [numpy.min(v[1]) for v in pairs]
  
      threshhold = numpy.percentile(losses, cutoff * 100)
  
      filteredValues = []
      filteredLosses = []
      for index in range(len(losses)):
          if losses[index] < threshhold:
              filteredValues.append((values[index]))
              filteredLosses.append((losses[index]))
  
      if len(filteredValues) < 2:
          filteredValues = values
          filteredLosses = losses
  
      if numBuckets is not None:
          buckets = self.computeBucketsForParameter(
              results, parameter, numBuckets
          )
  
          newLosses = []
          newValues = []
          for bucketIndex, bucket in enumerate(buckets):
              bucketLosses = []
              for valueIndex, value in enumerate(filteredValues):
                  if (bucketIndex == 0 and value <= bucket) or (
                      value > buckets[bucketIndex - 1]
                      and value <= bucket
                  ):
                      bucketLosses.append(filteredLosses[valueIndex])
              if len(bucketLosses) > 0:
                  if bucket_reduction == "mean":
                      newLosses.append(numpy.mean(bucketLosses))
                      newValues.append(bucket)
                  elif bucket_reduction == "min":
                      newLosses.append(numpy.min(bucketLosses))
                      newValues.append(bucket)
                  elif bucket_reduction == "median":
                      newLosses.append(numpy.median(bucketLosses))
                      newValues.append(bucket)
          filteredValues = newValues
          filteredLosses = newLosses
  
      bottom = numpy.min(filteredValues)
      top = numpy.max(filteredValues) + 1e-5
      trendLineXCoords = numpy.arange(bottom, top, (top - bottom) / 100)
  
      # If there are at least two results, we can fit a linear trend line
      linearTrendValues = None
      linearTrendLine = None
      if len(filteredLosses) > 2:
          z = numpy.polyfit(
              filteredValues, filteredLosses, 1, full=True
          )[0]
          p = numpy.poly1d(z)
          linearTrendValues = p(filteredValues)
          linearTrendLine = p(trendLineXCoords)
  
      medianValue = numpy.median(filteredValues)
      medianLoss = numpy.median(filteredLosses)
  
      # If there are at least three results, we can attempt to fit an exponential trend line
      exponentialTrendValues = None
      exponentialTrendLine = None
      if medianValue != 0:
          try:
              start_b = math.log10(medianLoss) / (-medianValue)
              # start_b = 1e-0
              if len(filteredLosses) > 2:
                  # Compute an exponential trend line
                  def exponenial_func(x, a, b, c):
                      return a * numpy.exp(-b * x) + c
  
                  warnings.simplefilter(
                      "ignore", scipy.optimize.OptimizeWarning
                  )
                  oldErrorSettings = numpy.seterr(all="ignore")
                  popt, pcov = scipy.optimize.curve_fit(
                      exponenial_func,
                      filteredValues,
                      filteredLosses,
                      p0=(1, start_b, 1),
                      bounds=(
                          [-numpy.inf, -abs(start_b * 1e1), -numpy.inf],
                          [+numpy.inf, +abs(start_b * 1e1), +numpy.inf],
                      ),
                  )
                  exponentialTrendValues = exponenial_func(
                      numpy.array(filteredValues).copy(), *popt
                  )
                  exponentialTrendLine = exponenial_func(
                      numpy.array(trendLineXCoords).copy(), *popt
                  )
                  numpy.seterr(**oldErrorSettings)
  
          except RuntimeError as e:
              # Scipy gives a run-time error if it fails to find an exponential curve that fits the data
              pass
  
      newResults = []
      for index in range(len(filteredLosses)):
          data = {
              parameter.root[5:]: filteredValues[index],
              valueKey: filteredLosses[index],
              "linearTrend": linearTrendValues[index]
              if linearTrendValues is not None
              else filteredLosses[index],
              "exponentialTrend": exponentialTrendValues[index]
              if exponentialTrendValues is not None
              else filteredLosses[index],
          }
  
          newResults.append(data)
  
      newResults = sorted(
          newResults, key=lambda val: val[parameter.root[5:]]
      )
  
      return (
          newResults,
          list(zip(trendLineXCoords, linearTrendLine))
          if linearTrendLine is not None
          else None,
          list(zip(trendLineXCoords, exponentialTrendLine))
          if exponentialTrendLine is not None
          else None,
      )
  
imports: import jsonschema
  import os
  import os.path
  import math
  import csv
  from hypermax.hyperparameter import Hyperparameter
  import sklearn.covariance
  import numpy
  from hypermax.utils import roundPrecision
  import matplotlib
  import matplotlib.cm
  import matplotlib.style
  import matplotlib.pyplot
  from pprint import pprint
  import concurrent.futures
  import colors
  import traceback
  import functools
  import warnings
  import scipy.optimize
  import random
  import json
  import atexit
  import matplotlib.ticker
  import traceback
  import copy
label_desc: Use image node_id 14 for calling the ResultsAnalyzer obj's underlying member method code with example usage: obj.computeParameterResultValues(results, parameter, valueKey, cutoff, numBuckets, bucket_reduction) and returns: newResults,  unknown,  unknown, unknown