class_docstr: Computes accuracy stats and a confusion matrix for the validation dataset 
code: def get_accuracy_stats(
      self, is_classification=None, is_numerical=None
  ):
      bucket_accuracy = {}
      bucket_acc_counts = {}
      for i, bucket in enumerate(self.normal_predictions_bucketized):
          if bucket not in bucket_acc_counts:
              bucket_acc_counts[bucket] = []
  
          if len(self.numerical_samples_arr) != 0:
              bucket_acc_counts[bucket].append(
                  self.numerical_samples_arr[i][1][0]
                  < self.numerical_samples_arr[i][0]
                  < self.numerical_samples_arr[i][1][1]
              )  # noqa
          else:
              bucket_acc_counts[bucket].append(
                  1 if bucket == self.real_values_bucketized[i] else 0
              )
  
      for bucket in bucket_acc_counts:
          bucket_accuracy[bucket] = sum(
              bucket_acc_counts[bucket]
          ) / len(bucket_acc_counts[bucket])
  
      accuracy_count = []
      for counts in list(bucket_acc_counts.values()):
          accuracy_count += counts
  
      overall_accuracy = round(
          sum(accuracy_count) / len(accuracy_count), self.n_decimals
      )
  
      for bucket in range(len(self.buckets)):
          if bucket not in bucket_accuracy:
              if bucket in self.real_values_bucketized:
                  # If it was never predicted, but it did exist as a real value, then assume 0% confidence when it does get predicted # noqa
                  bucket_accuracy[bucket] = 0
  
      for bucket in range(len(self.buckets)):
          if bucket not in bucket_accuracy:
              # If it wasn't seen either in the real values or in the predicted values, assume average confidence (maybe should be 0 instead ?) # noqa
              bucket_accuracy[bucket] = overall_accuracy
  
      accuracy_histogram = {
          "buckets": list(bucket_accuracy.keys()),
          "accuracies": list(bucket_accuracy.values()),
          "is_classification": is_classification,
          "is_numerical": is_numerical,
      }
  
      labels = list(
          set(
              [
                  *self.real_values_bucketized,
                  *self.normal_predictions_bucketized,
              ]
          )
      )
      matrix = confusion_matrix(
          self.real_values_bucketized,
          self.normal_predictions_bucketized,
          labels=labels,
      )
      matrix = [
          [int(y) if str(y) != "nan" else 0 for y in x] for x in matrix
      ]
  
      target_bucket = self.buckets[self.target]
      bucket_values = [
          target_bucket[i] if i < len(target_bucket) else None
          for i in labels
      ]
  
      cm = {
          "matrix": matrix,
          "predicted": bucket_values,
          "real": bucket_values,
      }
  
      accuracy_samples = None
      if len(self.numerical_samples_arr) > 0:
          nr_samples = min(400, len(self.numerical_samples_arr))
          sampled_numerical_samples_arr = random.sample(
              self.numerical_samples_arr, nr_samples
          )
          accuracy_samples = {
              "y": [x[0] for x in sampled_numerical_samples_arr],
              "x": [x[1] for x in sampled_numerical_samples_arr],
          }
  
      return overall_accuracy, accuracy_histogram, cm, accuracy_samples
  
file_path: lightwood/lightwood/analysis/helpers/acc_stats.py
imports: import random
  from types import SimpleNamespace
  from typing import Dict, Optional
  import numpy
  from sklearn.metrics import confusion_matrix
  from type_infer.dtype import dtype
  from lightwood.analysis.base import BaseAnalysisBlock
  from mindsdb_evaluator import evaluate_accuracies
label_desc: Use image node_id 4 for calling the AccStats obj's underlying member method code with example usage: obj.get_accuracy_stats(is_classification, is_numerical) and returns: overall_accuracy,  accuracy_histogram,  cm,  accuracy_samples