class_docstr: Wrapper analysis block for the 'PyOD' anomaly detection library.
  
  For now, the following techniques are supported:
    - SUOD: Large-scale unsupervised heterogeneous outlier detection
class_docstr_tok: ["Wrapper","analysis","block","for","the","'PyOD","'","anomaly","detection","library",".","For","now",",","the","following","techniques","are","supported",":","-","SUOD",":","Large-scale","unsupervised","heterogeneous","outlier","detection"]
code: def analyze(
      self, info: Dict[str, object], **kwargs
  ) -> Dict[str, object]:
      log.info("Preparing to compute anomaly detection with PyOD")
      ns = SimpleNamespace(**kwargs)
      self.target = ns.target
      detector_list = [
          LOF(n_neighbors=10, contamination=self.contamination),
          LOF(n_neighbors=30, contamination=self.contamination),
          HBOS(contamination=self.contamination),
          PCA(contamination=self.contamination),
      ]
  
      df = deepcopy(ns.train_data.data_frame)
      n_jobs = get_nr_procs(df)
      clf = SUOD(
          base_estimators=detector_list,
          contamination=self.contamination,
          n_jobs=n_jobs,
          combination="average",
          verbose=False,
      )
  
      if ns.tss.is_timeseries:
          for gcol in ns.tss.group_by:
              self.ordinal_encoders[gcol] = OrdinalEncoder(
                  handle_unknown="use_encoded_value", unknown_value=-1
              )
              self.ordinal_encoders[gcol].fit(
                  df[gcol].values.reshape(-1, 1)
              )
          for i in range(1, ns.tss.horizon):
              self.exceptions.append(f"{self.target}_timestep_{i}")
  
          self.exceptions.append(ns.tss.order_by)
          df = self._preprocess_ts_df(df, ns)
  
      for col in df.columns:
          if (
              col != self.target
              and "__mdb" not in col
              and col not in self.exceptions
          ):
              self.input_cols.append(col)
  
      df = df.loc[:, self.input_cols].dropna()
      clf.fit(df.values)
      info["pyod_explainer"] = clf
      return info
  
file_path: lightwood/lightwood/analysis/helpers/pyod.py
imports: from copy import deepcopy
  from types import SimpleNamespace
  from typing import Dict, Optional, Tuple
  import pandas
  import numpy
  from sklearn.preprocessing import OrdinalEncoder
  from pyod.models.lof import LOF
  from pyod.models.pca import PCA
  from pyod.models.hbos import HBOS
  from pyod.models.suod import SUOD
  from lightwood.analysis.base import BaseAnalysisBlock
  from lightwood.helpers.log import log
  from lightwood.helpers.parallelism import get_nr_procs
label_desc: Use image node_id 2 for calling the PyOD obj's underlying member method code with example usage: obj.analyze(info) and returns: info