All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ai.h2o.sparkling.ml.params.H2OStackedEnsembleParams.scala Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ai.h2o.sparkling.ml.params

import hex.ensemble.StackedEnsembleModel.StackedEnsembleParameters
import ai.h2o.sparkling.H2OFrame
import hex.ensemble.Metalearner.Algorithm
import hex.Model.Parameters.FoldAssignmentScheme
import hex.ensemble.StackedEnsembleModel.StackedEnsembleParameters.MetalearnerTransform
import hex.genmodel.utils.DistributionFamily
import hex.Model.Parameters.FoldAssignmentScheme
import hex.Model.Parameters.CategoricalEncodingScheme
import hex.ScoreKeeper.StoppingMetric
import hex.MultinomialAucType

trait H2OStackedEnsembleParams
  extends H2OAlgoParamsBase
  with HasBlendingDataFrame
  with HasBaseAlgorithms {


  //
  // Parameter definitions
  //
  protected val metalearnerAlgorithm = stringParam(
    name = "metalearnerAlgorithm",
    doc = """Type of algorithm to use as the metalearner. Options include 'AUTO' (GLM with non negative weights; if validation_frame is present, a lambda search is performed), 'deeplearning' (Deep Learning with default parameters), 'drf' (Random Forest with default parameters), 'gbm' (GBM with default parameters), 'glm' (GLM with default parameters), 'naivebayes' (NaiveBayes with default parameters), or 'xgboost' (if available, XGBoost with default parameters). Possible values are ``"AUTO"``, ``"deeplearning"``, ``"drf"``, ``"gbm"``, ``"glm"``, ``"naivebayes"``, ``"xgboost"``.""")

  protected val metalearnerNfolds = intParam(
    name = "metalearnerNfolds",
    doc = """Number of folds for K-fold cross-validation of the metalearner algorithm (0 to disable or >= 2).""")

  protected val metalearnerFoldAssignment = stringParam(
    name = "metalearnerFoldAssignment",
    doc = """Cross-validation fold assignment scheme for metalearner cross-validation.  Defaults to AUTO (which is currently set to Random). The 'Stratified' option will stratify the folds based on the response variable, for classification problems. Possible values are ``"AUTO"``, ``"Random"``, ``"Modulo"``, ``"Stratified"``.""")

  protected val metalearnerFoldCol = nullableStringParam(
    name = "metalearnerFoldCol",
    doc = """Column with cross-validation fold index assignment per observation for cross-validation of the metalearner.""")

  protected val metalearnerTransform = stringParam(
    name = "metalearnerTransform",
    doc = """Transformation used for the level one frame. Possible values are ``"NONE"``, ``"Logit"``.""")

  protected val keepLeveloneFrame = booleanParam(
    name = "keepLeveloneFrame",
    doc = """Keep level one frame used for metalearner training.""")

  protected val metalearnerParams = stringParam(
    name = "metalearnerParams",
    doc = """Parameters for metalearner algorithm.""")

  protected val seed = longParam(
    name = "seed",
    doc = """Seed for random numbers; passed through to the metalearner algorithm. Defaults to -1 (time-based random number).""")

  protected val scoreTrainingSamples = longParam(
    name = "scoreTrainingSamples",
    doc = """Specify the number of training set samples for scoring. The value must be >= 0. To use all training samples, enter 0.""")

  protected val modelId = nullableStringParam(
    name = "modelId",
    doc = """Destination id for this model; auto-generated if not specified.""")

  protected val nfolds = intParam(
    name = "nfolds",
    doc = """Number of folds for K-fold cross-validation (0 to disable or >= 2).""")

  protected val keepCrossValidationModels = booleanParam(
    name = "keepCrossValidationModels",
    doc = """Whether to keep the cross-validation models.""")

  protected val keepCrossValidationPredictions = booleanParam(
    name = "keepCrossValidationPredictions",
    doc = """Whether to keep the predictions of the cross-validation models.""")

  protected val keepCrossValidationFoldAssignment = booleanParam(
    name = "keepCrossValidationFoldAssignment",
    doc = """Whether to keep the cross-validation fold assignment.""")

  protected val parallelizeCrossValidation = booleanParam(
    name = "parallelizeCrossValidation",
    doc = """Allow parallel training of cross-validation models.""")

  protected val distribution = stringParam(
    name = "distribution",
    doc = """Distribution function. Possible values are ``"AUTO"``, ``"bernoulli"``, ``"quasibinomial"``, ``"modified_huber"``, ``"multinomial"``, ``"ordinal"``, ``"gaussian"``, ``"poisson"``, ``"gamma"``, ``"tweedie"``, ``"huber"``, ``"laplace"``, ``"quantile"``, ``"fractionalbinomial"``, ``"negativebinomial"``, ``"custom"``.""")

  protected val tweediePower = doubleParam(
    name = "tweediePower",
    doc = """Tweedie power for Tweedie regression, must be between 1 and 2.""")

  protected val quantileAlpha = doubleParam(
    name = "quantileAlpha",
    doc = """Desired quantile for Quantile regression, must be between 0 and 1.""")

  protected val huberAlpha = doubleParam(
    name = "huberAlpha",
    doc = """Desired quantile for Huber/M-regression (threshold between quadratic and linear loss, must be between 0 and 1).""")

  protected val labelCol = nullableStringParam(
    name = "labelCol",
    doc = """Response variable column.""")

  protected val weightCol = nullableStringParam(
    name = "weightCol",
    doc = """Column with observation weights. Giving some observation a weight of zero is equivalent to excluding it from the dataset; giving an observation a relative weight of 2 is equivalent to repeating that row twice. Negative weights are not allowed. Note: Weights are per-row observation weights and do not increase the size of the data frame. This is typically the number of times a row is repeated, but non-integer values are supported as well. During training, rows with higher weights matter more, due to the larger loss function pre-factor. If you set weight = 0 for a row, the returned prediction frame at that row is zero and this is incorrect. To get an accurate prediction, remove all rows with weight == 0.""")

  protected val offsetCol = nullableStringParam(
    name = "offsetCol",
    doc = """Offset column. This will be added to the combination of columns before applying the link function.""")

  protected val foldCol = nullableStringParam(
    name = "foldCol",
    doc = """Column with cross-validation fold index assignment per observation.""")

  protected val foldAssignment = stringParam(
    name = "foldAssignment",
    doc = """Cross-validation fold assignment scheme, if fold_column is not specified. The 'Stratified' option will stratify the folds based on the response variable, for classification problems. Possible values are ``"AUTO"``, ``"Random"``, ``"Modulo"``, ``"Stratified"``.""")

  protected val categoricalEncoding = stringParam(
    name = "categoricalEncoding",
    doc = """Encoding scheme for categorical features. Possible values are ``"AUTO"``, ``"OneHotInternal"``, ``"OneHotExplicit"``, ``"Enum"``, ``"Binary"``, ``"Eigen"``, ``"LabelEncoder"``, ``"SortByResponse"``, ``"EnumLimited"``.""")

  protected val maxCategoricalLevels = intParam(
    name = "maxCategoricalLevels",
    doc = """For every categorical feature, only use this many most frequent categorical levels for model training. Only used for categorical_encoding == EnumLimited.""")

  protected val ignoredCols = nullableStringArrayParam(
    name = "ignoredCols",
    doc = """Names of columns to ignore for training.""")

  protected val ignoreConstCols = booleanParam(
    name = "ignoreConstCols",
    doc = """Ignore constant columns.""")

  protected val scoreEachIteration = booleanParam(
    name = "scoreEachIteration",
    doc = """Whether to score during each iteration of model training.""")

  protected val checkpoint = nullableStringParam(
    name = "checkpoint",
    doc = """Model checkpoint to resume training with.""")

  protected val stoppingRounds = intParam(
    name = "stoppingRounds",
    doc = """Early stopping based on convergence of stopping_metric. Stop if simple moving average of length k of the stopping_metric does not improve for k:=stopping_rounds scoring events (0 to disable).""")

  protected val maxRuntimeSecs = doubleParam(
    name = "maxRuntimeSecs",
    doc = """Maximum allowed runtime in seconds for model training. Use 0 to disable.""")

  protected val stoppingMetric = stringParam(
    name = "stoppingMetric",
    doc = """Metric to use for early stopping (AUTO: logloss for classification, deviance for regression and anomaly_score for Isolation Forest). Note that custom and custom_increasing can only be used in GBM and DRF with the Python client. Possible values are ``"AUTO"``, ``"deviance"``, ``"logloss"``, ``"MSE"``, ``"RMSE"``, ``"MAE"``, ``"RMSLE"``, ``"AUC"``, ``"AUCPR"``, ``"lift_top_group"``, ``"misclassification"``, ``"mean_per_class_error"``, ``"anomaly_score"``, ``"AUUC"``, ``"ATE"``, ``"ATT"``, ``"ATC"``, ``"qini"``, ``"custom"``, ``"custom_increasing"``.""")

  protected val stoppingTolerance = doubleParam(
    name = "stoppingTolerance",
    doc = """Relative tolerance for metric-based stopping criterion (stop if relative improvement is not at least this much).""")

  protected val gainsliftBins = intParam(
    name = "gainsliftBins",
    doc = """Gains/Lift table number of bins. 0 means disabled.. Default value -1 means automatic binning.""")

  protected val customMetricFunc = nullableStringParam(
    name = "customMetricFunc",
    doc = """Reference to custom evaluation function, format: `language:keyName=funcName`.""")

  protected val customDistributionFunc = nullableStringParam(
    name = "customDistributionFunc",
    doc = """Reference to custom distribution, format: `language:keyName=funcName`.""")

  protected val exportCheckpointsDir = nullableStringParam(
    name = "exportCheckpointsDir",
    doc = """Automatically export generated models to this directory.""")

  protected val aucType = stringParam(
    name = "aucType",
    doc = """Set default multinomial AUC type. Possible values are ``"AUTO"``, ``"NONE"``, ``"MACRO_OVR"``, ``"WEIGHTED_OVR"``, ``"MACRO_OVO"``, ``"WEIGHTED_OVO"``.""")

  //
  // Default values
  //
  setDefault(
    metalearnerAlgorithm -> Algorithm.AUTO.name(),
    metalearnerNfolds -> 0,
    metalearnerFoldAssignment -> FoldAssignmentScheme.AUTO.name(),
    metalearnerFoldCol -> null,
    metalearnerTransform -> MetalearnerTransform.NONE.name(),
    keepLeveloneFrame -> false,
    metalearnerParams -> "",
    seed -> -1L,
    scoreTrainingSamples -> 10000L,
    modelId -> null,
    nfolds -> 0,
    keepCrossValidationModels -> true,
    keepCrossValidationPredictions -> false,
    keepCrossValidationFoldAssignment -> false,
    parallelizeCrossValidation -> true,
    distribution -> DistributionFamily.AUTO.name(),
    tweediePower -> 1.5,
    quantileAlpha -> 0.5,
    huberAlpha -> 0.9,
    labelCol -> null,
    weightCol -> null,
    offsetCol -> null,
    foldCol -> null,
    foldAssignment -> FoldAssignmentScheme.AUTO.name(),
    categoricalEncoding -> CategoricalEncodingScheme.AUTO.name(),
    maxCategoricalLevels -> 10,
    ignoredCols -> null,
    ignoreConstCols -> true,
    scoreEachIteration -> false,
    checkpoint -> null,
    stoppingRounds -> 0,
    maxRuntimeSecs -> 0.0,
    stoppingMetric -> StoppingMetric.AUTO.name(),
    stoppingTolerance -> 0.001,
    gainsliftBins -> -1,
    customMetricFunc -> null,
    customDistributionFunc -> null,
    exportCheckpointsDir -> null,
    aucType -> MultinomialAucType.AUTO.name())

  //
  // Getters
  //
  def getMetalearnerAlgorithm(): String = $(metalearnerAlgorithm)

  def getMetalearnerNfolds(): Int = $(metalearnerNfolds)

  def getMetalearnerFoldAssignment(): String = $(metalearnerFoldAssignment)

  def getMetalearnerFoldCol(): String = $(metalearnerFoldCol)

  def getMetalearnerTransform(): String = $(metalearnerTransform)

  def getKeepLeveloneFrame(): Boolean = $(keepLeveloneFrame)

  def getMetalearnerParams(): String = $(metalearnerParams)

  def getSeed(): Long = $(seed)

  def getScoreTrainingSamples(): Long = $(scoreTrainingSamples)

  def getModelId(): String = $(modelId)

  def getNfolds(): Int = $(nfolds)

  def getKeepCrossValidationModels(): Boolean = $(keepCrossValidationModels)

  def getKeepCrossValidationPredictions(): Boolean = $(keepCrossValidationPredictions)

  def getKeepCrossValidationFoldAssignment(): Boolean = $(keepCrossValidationFoldAssignment)

  def getParallelizeCrossValidation(): Boolean = $(parallelizeCrossValidation)

  def getDistribution(): String = $(distribution)

  def getTweediePower(): Double = $(tweediePower)

  def getQuantileAlpha(): Double = $(quantileAlpha)

  def getHuberAlpha(): Double = $(huberAlpha)

  def getLabelCol(): String = $(labelCol)

  def getWeightCol(): String = $(weightCol)

  def getOffsetCol(): String = $(offsetCol)

  def getFoldCol(): String = $(foldCol)

  def getFoldAssignment(): String = $(foldAssignment)

  def getCategoricalEncoding(): String = $(categoricalEncoding)

  def getMaxCategoricalLevels(): Int = $(maxCategoricalLevels)

  def getIgnoredCols(): Array[String] = $(ignoredCols)

  def getIgnoreConstCols(): Boolean = $(ignoreConstCols)

  def getScoreEachIteration(): Boolean = $(scoreEachIteration)

  def getCheckpoint(): String = $(checkpoint)

  def getStoppingRounds(): Int = $(stoppingRounds)

  def getMaxRuntimeSecs(): Double = $(maxRuntimeSecs)

  def getStoppingMetric(): String = $(stoppingMetric)

  def getStoppingTolerance(): Double = $(stoppingTolerance)

  def getGainsliftBins(): Int = $(gainsliftBins)

  def getCustomMetricFunc(): String = $(customMetricFunc)

  def getCustomDistributionFunc(): String = $(customDistributionFunc)

  def getExportCheckpointsDir(): String = $(exportCheckpointsDir)

  def getAucType(): String = $(aucType)

  //
  // Setters
  //
  def setMetalearnerAlgorithm(value: String): this.type = {
    val validated = EnumParamValidator.getValidatedEnumValue[Algorithm](value)
    set(metalearnerAlgorithm, validated)
  }
           
  def setMetalearnerNfolds(value: Int): this.type = {
    set(metalearnerNfolds, value)
  }
           
  def setMetalearnerFoldAssignment(value: String): this.type = {
    val validated = EnumParamValidator.getValidatedEnumValue[FoldAssignmentScheme](value)
    set(metalearnerFoldAssignment, validated)
  }
           
  def setMetalearnerFoldCol(value: String): this.type = {
    set(metalearnerFoldCol, value)
  }
           
  def setMetalearnerTransform(value: String): this.type = {
    val validated = EnumParamValidator.getValidatedEnumValue[MetalearnerTransform](value)
    set(metalearnerTransform, validated)
  }
           
  def setKeepLeveloneFrame(value: Boolean): this.type = {
    set(keepLeveloneFrame, value)
  }
           
  def setMetalearnerParams(value: String): this.type = {
    set(metalearnerParams, value)
  }
           
  def setSeed(value: Long): this.type = {
    set(seed, value)
  }
           
  def setScoreTrainingSamples(value: Long): this.type = {
    set(scoreTrainingSamples, value)
  }
           
  def setModelId(value: String): this.type = {
    set(modelId, value)
  }
           
  def setNfolds(value: Int): this.type = {
    set(nfolds, value)
  }
           
  def setKeepCrossValidationModels(value: Boolean): this.type = {
    set(keepCrossValidationModels, value)
  }
           
  def setKeepCrossValidationPredictions(value: Boolean): this.type = {
    set(keepCrossValidationPredictions, value)
  }
           
  def setKeepCrossValidationFoldAssignment(value: Boolean): this.type = {
    set(keepCrossValidationFoldAssignment, value)
  }
           
  def setParallelizeCrossValidation(value: Boolean): this.type = {
    set(parallelizeCrossValidation, value)
  }
           
  def setDistribution(value: String): this.type = {
    val validated = EnumParamValidator.getValidatedEnumValue[DistributionFamily](value)
    set(distribution, validated)
  }
           
  def setTweediePower(value: Double): this.type = {
    set(tweediePower, value)
  }
           
  def setQuantileAlpha(value: Double): this.type = {
    set(quantileAlpha, value)
  }
           
  def setHuberAlpha(value: Double): this.type = {
    set(huberAlpha, value)
  }
           
  def setLabelCol(value: String): this.type = {
    set(labelCol, value)
  }
           
  def setWeightCol(value: String): this.type = {
    set(weightCol, value)
  }
           
  def setOffsetCol(value: String): this.type = {
    set(offsetCol, value)
  }
           
  def setFoldCol(value: String): this.type = {
    set(foldCol, value)
  }
           
  def setFoldAssignment(value: String): this.type = {
    val validated = EnumParamValidator.getValidatedEnumValue[FoldAssignmentScheme](value)
    set(foldAssignment, validated)
  }
           
  def setCategoricalEncoding(value: String): this.type = {
    val validated = EnumParamValidator.getValidatedEnumValue[CategoricalEncodingScheme](value)
    set(categoricalEncoding, validated)
  }
           
  def setMaxCategoricalLevels(value: Int): this.type = {
    set(maxCategoricalLevels, value)
  }
           
  def setIgnoredCols(value: Array[String]): this.type = {
    set(ignoredCols, value)
  }
           
  def setIgnoreConstCols(value: Boolean): this.type = {
    set(ignoreConstCols, value)
  }
           
  def setScoreEachIteration(value: Boolean): this.type = {
    set(scoreEachIteration, value)
  }
           
  def setCheckpoint(value: String): this.type = {
    set(checkpoint, value)
  }
           
  def setStoppingRounds(value: Int): this.type = {
    set(stoppingRounds, value)
  }
           
  def setMaxRuntimeSecs(value: Double): this.type = {
    set(maxRuntimeSecs, value)
  }
           
  def setStoppingMetric(value: String): this.type = {
    val validated = EnumParamValidator.getValidatedEnumValue[StoppingMetric](value)
    set(stoppingMetric, validated)
  }
           
  def setStoppingTolerance(value: Double): this.type = {
    set(stoppingTolerance, value)
  }
           
  def setGainsliftBins(value: Int): this.type = {
    set(gainsliftBins, value)
  }
           
  def setCustomMetricFunc(value: String): this.type = {
    set(customMetricFunc, value)
  }
           
  def setCustomDistributionFunc(value: String): this.type = {
    set(customDistributionFunc, value)
  }
           
  def setExportCheckpointsDir(value: String): this.type = {
    set(exportCheckpointsDir, value)
  }
           
  def setAucType(value: String): this.type = {
    val validated = EnumParamValidator.getValidatedEnumValue[MultinomialAucType](value)
    set(aucType, validated)
  }
           

  override private[sparkling] def getH2OAlgorithmParams(trainingFrame: H2OFrame): Map[String, Any] = {
    super.getH2OAlgorithmParams(trainingFrame) ++ getH2OStackedEnsembleParams(trainingFrame)
  }

  private[sparkling] def getH2OStackedEnsembleParams(trainingFrame: H2OFrame): Map[String, Any] = {
      Map(
        "metalearner_algorithm" -> getMetalearnerAlgorithm(),
        "metalearner_nfolds" -> getMetalearnerNfolds(),
        "metalearner_fold_assignment" -> getMetalearnerFoldAssignment(),
        "metalearner_fold_column" -> getMetalearnerFoldCol(),
        "metalearner_transform" -> getMetalearnerTransform(),
        "keep_levelone_frame" -> getKeepLeveloneFrame(),
        "metalearner_params" -> getMetalearnerParams(),
        "seed" -> getSeed(),
        "score_training_samples" -> getScoreTrainingSamples(),
        "model_id" -> getModelId(),
        "nfolds" -> getNfolds(),
        "keep_cross_validation_models" -> getKeepCrossValidationModels(),
        "keep_cross_validation_predictions" -> getKeepCrossValidationPredictions(),
        "keep_cross_validation_fold_assignment" -> getKeepCrossValidationFoldAssignment(),
        "parallelize_cross_validation" -> getParallelizeCrossValidation(),
        "distribution" -> getDistribution(),
        "tweedie_power" -> getTweediePower(),
        "quantile_alpha" -> getQuantileAlpha(),
        "huber_alpha" -> getHuberAlpha(),
        "response_column" -> getLabelCol(),
        "weights_column" -> getWeightCol(),
        "offset_column" -> getOffsetCol(),
        "fold_column" -> getFoldCol(),
        "fold_assignment" -> getFoldAssignment(),
        "categorical_encoding" -> getCategoricalEncoding(),
        "max_categorical_levels" -> getMaxCategoricalLevels(),
        "ignored_columns" -> getIgnoredCols(),
        "ignore_const_cols" -> getIgnoreConstCols(),
        "score_each_iteration" -> getScoreEachIteration(),
        "checkpoint" -> getCheckpoint(),
        "stopping_rounds" -> getStoppingRounds(),
        "max_runtime_secs" -> getMaxRuntimeSecs(),
        "stopping_metric" -> getStoppingMetric(),
        "stopping_tolerance" -> getStoppingTolerance(),
        "gainslift_bins" -> getGainsliftBins(),
        "custom_metric_func" -> getCustomMetricFunc(),
        "custom_distribution_func" -> getCustomDistributionFunc(),
        "export_checkpoints_dir" -> getExportCheckpointsDir(),
        "auc_type" -> getAucType()) +++
      getBlendingDataFrameParam(trainingFrame) +++
      getBaseAlgorithmsParam(trainingFrame)
  }

  override private[sparkling] def getSWtoH2OParamNameMap(): Map[String, String] = {
    super.getSWtoH2OParamNameMap() ++
      Map(
        "metalearnerAlgorithm" -> "metalearner_algorithm",
        "metalearnerNfolds" -> "metalearner_nfolds",
        "metalearnerFoldAssignment" -> "metalearner_fold_assignment",
        "metalearnerFoldCol" -> "metalearner_fold_column",
        "metalearnerTransform" -> "metalearner_transform",
        "keepLeveloneFrame" -> "keep_levelone_frame",
        "metalearnerParams" -> "metalearner_params",
        "seed" -> "seed",
        "scoreTrainingSamples" -> "score_training_samples",
        "modelId" -> "model_id",
        "nfolds" -> "nfolds",
        "keepCrossValidationModels" -> "keep_cross_validation_models",
        "keepCrossValidationPredictions" -> "keep_cross_validation_predictions",
        "keepCrossValidationFoldAssignment" -> "keep_cross_validation_fold_assignment",
        "parallelizeCrossValidation" -> "parallelize_cross_validation",
        "distribution" -> "distribution",
        "tweediePower" -> "tweedie_power",
        "quantileAlpha" -> "quantile_alpha",
        "huberAlpha" -> "huber_alpha",
        "labelCol" -> "response_column",
        "weightCol" -> "weights_column",
        "offsetCol" -> "offset_column",
        "foldCol" -> "fold_column",
        "foldAssignment" -> "fold_assignment",
        "categoricalEncoding" -> "categorical_encoding",
        "maxCategoricalLevels" -> "max_categorical_levels",
        "ignoredCols" -> "ignored_columns",
        "ignoreConstCols" -> "ignore_const_cols",
        "scoreEachIteration" -> "score_each_iteration",
        "checkpoint" -> "checkpoint",
        "stoppingRounds" -> "stopping_rounds",
        "maxRuntimeSecs" -> "max_runtime_secs",
        "stoppingMetric" -> "stopping_metric",
        "stoppingTolerance" -> "stopping_tolerance",
        "gainsliftBins" -> "gainslift_bins",
        "customMetricFunc" -> "custom_metric_func",
        "customDistributionFunc" -> "custom_distribution_func",
        "exportCheckpointsDir" -> "export_checkpoints_dir",
        "aucType" -> "auc_type")
  }
      
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy