class_docstr: Computes accuracy stats and a confusion matrix for the validation dataset 
code: def fit(self, ns: SimpleNamespace, conf=Optional[np.ndarray]):
      self.col_stats = ns.dtype_dict
      self.target = ns.target
      self.input_cols = ns.input_cols
      self.buckets = (
          ns.stats_info.buckets if ns.stats_info.buckets else {}
      )
  
      self.normal_predictions_bucketized = []
      self.real_values_bucketized = []
      self.numerical_samples_arr = []
  
      for n in range(len(ns.normal_predictions)):
          row = ns.data.iloc[n]
          real_value = row[self.target]
          predicted_value = ns.normal_predictions.iloc[n]["prediction"]
  
          if isinstance(predicted_value, list):
              # T+N time series, for now we compare the T+1 prediction only @TODO: generalize
              predicted_value = predicted_value[0]
  
          predicted_value = (
              predicted_value
              if self.col_stats[self.target]
              not in [dtype.integer, dtype.float, dtype.quantity]
              else float(predicted_value)
          )
  
          real_value = (
              real_value
              if self.col_stats[self.target]
              not in [dtype.integer, dtype.float, dtype.quantity]
              else float(real_value)
          )
  
          if self.buckets:
              bucket = self.buckets[self.target]
              predicted_value_b = get_value_bucket(
                  predicted_value, bucket, self.col_stats[self.target]
              )
              real_value_b = get_value_bucket(
                  real_value, bucket, self.col_stats[self.target]
              )
          else:
              predicted_value_b = predicted_value
              real_value_b = real_value
  
          if conf is not None and self.col_stats[self.target] in [
              dtype.integer,
              dtype.float,
              dtype.quantity,
          ]:
              predicted_range = conf.iloc[n][
                  ["lower", "upper"]
              ].tolist()
          else:
              predicted_range = (predicted_value_b, predicted_value_b)
  
          self.real_values_bucketized.append(real_value_b)
          self.normal_predictions_bucketized.append(predicted_value_b)
          if conf is not None and self.col_stats[self.target] in [
              dtype.integer,
              dtype.float,
              dtype.quantity,
          ]:
              self.numerical_samples_arr.append(
                  (real_value, predicted_range)
              )
  
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 3 for calling the AccStats obj's underlying member method code with example usage: obj.fit(ns, conf) without return types