docs: def _get_xy_dataset_statistics(x_values, y_values,
                                 fcorrect_x_cutoff = 1.0, fcorrect_y_cutoff = 1.0, x_fuzzy_range = 0.1, y_scalar = 1.0,
                                 ignore_null_values = False, bootstrap_data = False,
                                 expect_negative_correlation = False, STDev_cutoff = 1.0,
                                 run_standardized_analysis = True,
                                 check_multiple_analysis_for_consistency = True):
      '''
      A function which takes two lists of values of equal length with corresponding entries and returns a dict containing
      a variety of metrics.
      :param x_values: A list of values for the X-axis (experimental values).
      :param y_values: A list of values for the X-axis (predicted values).
      :param fcorrect_x_cutoff: See get_xy_dataset_statistics.
      :param fcorrect_y_cutoff: See get_xy_dataset_statistics.
      :param x_fuzzy_range: See get_xy_dataset_statistics.
      :param y_scalar: See get_xy_dataset_statistics.
      :param ignore_null_values: Remove records with missing data before running analysis.
      :param bootstrap_data: Set to True to enable bootstrapping. Bootstrapping data to estimate errors is an expensive operation so is disabled by default.
      :param expect_negative_correlation: See klab.benchmarking.analysis.ssm::parse_csv().
      :param STDev_cutoff: See klab.benchmarking.analysis.ssm::parse_csv().
      :return: A table of statistics.
      '''
      assert(len(x_values) == len(y_values))
  
      num_null_cases = 0
      if ignore_null_values:
          truncated_x_values, truncated_y_values = [], []
          for i in xrange(len(x_values)):
              if (x_values[i] == None) or (numpy.isnan(x_values[i])):
                  num_null_cases += 1
              elif (y_values[i] == None) or (numpy.isnan(y_values[i])):
                  num_null_cases += 1
              else:
                  truncated_x_values.append(x_values[i])
                  truncated_y_values.append(y_values[i])
          x_values = truncated_x_values
          y_values = truncated_y_values
  
      stats = dict(
          pearsonr = pearsonr(x_values, y_values),
          spearmanr = spearmanr(x_values, y_values),
          gamma_CC = gamma_CC(x_values, y_values),
          MAE = mae(x_values, y_values),
          normaltestx = normaltest_check(x_values),
          normaltesty = normaltest_check(y_values),
          kstestx = kstest(x_values, 'norm'),
          kstesty = kstest(y_values, 'norm'),
          ks_2samp = ks_2samp(x_values, y_values),
          fraction_correct = fraction_correct(x_values, y_values, x_cutoff = fcorrect_x_cutoff, y_cutoff = fcorrect_y_cutoff, ignore_null_values = ignore_null_values),
          fraction_correct_fuzzy_linear = fraction_correct_fuzzy_linear(x_values, y_values, x_cutoff = fcorrect_x_cutoff, y_cutoff = fcorrect_y_cutoff, x_fuzzy_range = x_fuzzy_range, y_scalar = y_scalar),
          n = len(x_values),
          num_null_cases = num_null_cases,
      )
      if bootstrap_data:
          stats.update(dict(
              pearsonr_error = bootstrap_xy_stat(x_values, y_values, pearsonr),
              MAE_error = bootstrap_xy_stat(x_values, y_values, mae),
              fraction_correct_error = bootstrap_xy_stat(x_values, y_values, fraction_correct, func_kwargs = {'x_cutoff' : fcorrect_x_cutoff, 'y_cutoff' : fcorrect_y_cutoff, 'ignore_null_values' : ignore_null_values}),
          ))
  
      # Call Samuel Thompson's analysis which uses confidence intervals when considering fraction correct-like metrics
      if run_standardized_analysis:
          std_stats = get_std_xy_dataset_statistics(x_values, y_values, expect_negative_correlation = expect_negative_correlation, STDev_cutoff = STDev_cutoff)
          fields_to_remove = []
          if check_multiple_analysis_for_consistency:
              # Make sure that any common analysis agrees
              fields_to_remove = sorted(set(std_stats.keys()).intersection(stats.keys()))
              for common_stat in fields_to_remove:
                  s1, s2 = std_stats[common_stat], stats[common_stat]
                  if isinstance(s1, tuple):
                      s1 = s1[0]
                  if isinstance(s2, tuple):
                      s2 = s2[0]
                  assert(abs(s1 - s2) < 0.001)
              for f in fields_to_remove:
                  del std_stats[f]
  
          stats.update(std_stats)
  
      return stats