class_docstr: This is the AccessAnomaly, a pyspark.ml.Estimator which
  creates the AccessAnomalyModel which is a pyspark.ml.Transformer
code: def __init__(
      self,
      tenantCol: str = AccessAnomalyConfig.default_tenant_col,
      userCol: str = AccessAnomalyConfig.default_user_col,
      resCol: str = AccessAnomalyConfig.default_res_col,
      likelihoodCol: str = AccessAnomalyConfig.default_likelihood_col,
      outputCol: str = AccessAnomalyConfig.default_output_col,
      rankParam: int = AccessAnomalyConfig.default_rank,
      maxIter: int = AccessAnomalyConfig.default_max_iter,
      regParam: float = AccessAnomalyConfig.default_reg_param,
      numBlocks: Optional[int] = AccessAnomalyConfig.default_num_blocks,
      separateTenants: bool = AccessAnomalyConfig.default_separate_tenants,
      lowValue: Optional[float] = AccessAnomalyConfig.default_low_value,
      highValue: Optional[
          float
      ] = AccessAnomalyConfig.default_high_value,
      applyImplicitCf: bool = AccessAnomalyConfig.default_apply_implicit_cf,
      alphaParam: Optional[float] = None,
      complementsetFactor: Optional[int] = None,
      negScore: Optional[float] = None,
      historyAccessDf: Optional[DataFrame] = None,
  ):
      super().__init__()
  
      if applyImplicitCf:
          alphaParam = (
              alphaParam
              if alphaParam is not None
              else AccessAnomalyConfig.default_alpha
          )
          assert complementsetFactor is None and negScore is None
      else:
          assert alphaParam is None
  
          complementsetFactor = (
              complementsetFactor
              if complementsetFactor is not None
              else AccessAnomalyConfig.default_complementset_factor
          )
  
          negScore = (
              negScore
              if negScore is not None
              else AccessAnomalyConfig.default_neg_score
          )
  
      # must either both be None or both be not None
      assert (lowValue is None) == (highValue is None)
      assert lowValue is None or lowValue >= 1.0
      assert (
          lowValue is None or highValue is None
      ) or highValue > lowValue
      assert (lowValue is None or negScore is None) or (
          lowValue is not None and negScore < lowValue
      )
  
      spark_utils.ExplainBuilder.build(
          self,
          tenantCol=tenantCol,
          userCol=userCol,
          resCol=resCol,
          likelihoodCol=likelihoodCol,
          outputCol=outputCol,
          rankParam=rankParam,
          maxIter=maxIter,
          regParam=regParam,
          numBlocks=numBlocks,
          separateTenants=separateTenants,
          lowValue=lowValue,
          highValue=highValue,
          applyImplicitCf=applyImplicitCf,
          alphaParam=alphaParam,
          complementsetFactor=complementsetFactor,
          negScore=negScore,
          historyAccessDf=historyAccessDf,
      )
  
imports: import os
  from typing import List, Optional, Tuple
  from synapse.ml.cyber.anomaly.complement_access import ComplementAccessTransformer
  from synapse.ml.cyber.feature import indexers, scalers
  from synapse.ml.cyber.utils import spark_utils
  import numpy
  from pyspark import SQLContext
  from pyspark.ml import Estimator, Transformer
  from pyspark.ml.param.shared import Param, Params
  from pyspark.ml.recommendation import ALS
  from pyspark.sql import DataFrame, functions, types
label_desc: Use image node_id 1 to create a new AccessAnomaly object from inherited base classes: Estimator with example: obj = AccessAnomaly(tenantCol, userCol, resCol, likelihoodCol, outputCol, rankParam, maxIter, regParam, numBlocks, separateTenants, lowValue, highValue, applyImplicitCf, alphaParam, complementsetFactor, negScore, historyAccessDf)