【问题标题】:Can we give a custom metric for cross-validation with GLM in H2O?我们可以为 H2O 中的 GLM 交叉验证提供自定义指标吗?
【发布时间】:2020-01-28 01:45:01
【问题描述】:

我正在尝试使用h2o.glm 通过交叉验证找到最佳惩罚lambda。这是一个多项式模型。

但是,我看到它正在根据多项式偏差进行优化。我可以对其他一些指标进行交叉验证,例如误分类错误吗?

文档中提到了参数custom_metric_func,但我不清楚它的描述。该指标是否用作交叉验证分数?如果是,文档还声明它仅在 Python API 中可用。这是真的吗?

【问题讨论】:

    标签: python r h2o


    【解决方案1】:

    如果您确实在使用 h2o,那么不将 R 界面留给 h2o 的合适选项是使用选项keep_cross_validation_models = TRUE, keep_cross_validation_predictions = TRUE,。由此,您可以在每个模型上构建每个类别的错误分类错误,每个模型都配有特定的 lambda 值序列。或者,您可以循环或遍历一系列 lambda。例如for (i in lambda_vector){ models[[i]]= h2o.glm(...,lambda= i )}。每个对象都有一个混淆矩阵,因此您可以潜在地计算每个类别的分类错误。您可以制定自己的选择标准。自定义指标仅在 python 中有效。

    如果你只能使用 R:

    为了拟合具有弹性惩罚的多项式模型,如果没有特定的理由与 h2o 相关联,我建议使用包 glmnet,它提供带有选项 family= 的命令 cv.glmnet() “多项式”和 type.measure="class"。这将产生一个通过对分类错误的交叉验证选择的多项模型。

    【讨论】:

    • 这些是解决 R API 限制的有用建议。但是,我想确认一下:您是说使用 Python API,custom_metric_func 将按照我想要的方式进行交叉验证吗?文档中并不清楚这个选项到底是做什么的。是的,我需要使用 R,因为它具有文档生成能力。另一种可能的解决方法是使用 reticulate 从 R 调用 Python API。是的,我已经使用了glmnet,但是 H2O 有更多关于特征重要性的统计数据,而 glmnet 缺乏,我不确定他们的公式是什么。
    • 免责声明我没有在 R 中尝试过。您在 script.py 中编写自定义指标:mymetric 并将其上传到集群,如this link 然后指定选项custom_metric_function=mymetric。这绝对适用于python。您可以在 R 中对其进行测试。由于该函数在集群中,我想您应该能够在 R 中访问它。但这只是一个猜测。
    • 我无法理解您提供的链接中的自定义指标代码。例如,他们对mapreducemetric 的描述根本就不清楚。所以我实现了我自己的 lambda 循环,类似于你描述的,但使用 h2o.grid 在 labmda 上进行网格搜索。我将在单独的答案中发布。
    • 太好了,我很高兴你知道了
    • 谢谢,但最好弄清楚如何使用他们的custom_metric_func
    【解决方案2】:

    我写了h2o.glm_custom 作为h2o.glm 的“替换”,它保留了交叉验证模型,以便可以在后面使用自定义选择标准,正如@Diegolog 所建议的那样。我的方法使用h2o.grid。我试图包含h2o.glm 的所有参数,但简化了一些默认值以避免额外的工作。

    h2o.glm_custom <- function(x,
                               y,
                               training_frame,
                               model_id = NULL,
                               validation_frame = NULL,
                               nfolds = 0,
                               seed = -1,
                               keep_cross_validation_models = TRUE,
                               keep_cross_validation_predictions = FALSE,
                               keep_cross_validation_fold_assignment = FALSE,
                               fold_assignment = "AUTO",
                               fold_column = NULL,
                               random_columns = NULL,
                               ignore_const_cols = TRUE,
                               score_each_iteration = FALSE,
                               offset_column = NULL,
                               weights_column = NULL,
                               family = "binomial",
                               rand_family = c("[gaussian]"),
                               tweedie_variance_power = 0,
                               tweedie_link_power = 1,
                               theta = 1e-10,
                               solver = "AUTO",
                               alpha = 0,
                               early_stopping = TRUE,
                               nlambdas = 100,
                               standardize = TRUE,
                               missing_values_handling = "MeanImputation",
                               plug_values = NULL,
                               compute_p_values = FALSE,
                               remove_collinear_columns = FALSE,
                               intercept = TRUE,
                               non_negative = FALSE,
                               max_iterations = -1,
                               objective_epsilon = -1,
                               beta_epsilon = 1e-04,
                               gradient_epsilon = -1,
                               link = "family_default",
                               rand_link = "[identity]",
                               startval = NULL,
                               calc_like = FALSE,
                               HGLM = FALSE,
                               prior = -1,
                               lambda_min_ratio = 0.01,
                               beta_constraints = NULL,
                               max_active_predictors = -1,
                               obj_reg = -1,
                               export_checkpoints_dir = NULL,
                               balance_classes = FALSE,
                               class_sampling_factors = NULL,
                               max_after_balance_size = 5,
                               max_hit_ratio_k = 0,
                               max_runtime_secs = 0,
                               custom_metric_func = NULL) {
    
      # Find lambda_max
      model <- h2o.glm(x,
                       y,
                       training_frame,
                       model_id,
                       validation_frame,
                       nfolds,
                       seed,
                       keep_cross_validation_models,
                       keep_cross_validation_predictions,
                       keep_cross_validation_fold_assignment,
                       fold_assignment,
                       fold_column,
                       random_columns,
                       ignore_const_cols,
                       score_each_iteration,
                       offset_column,
                       weights_column,
                       family,
                       rand_family,
                       tweedie_variance_power,
                       tweedie_link_power,
                       theta,
                       solver,
                       alpha,
                       NULL, # lambda
                       TRUE, # lambda_search
                       early_stopping,
                       1, # nlambdas
                       standardize,
                       missing_values_handling,
                       plug_values,
                       compute_p_values,
                       remove_collinear_columns,
                       intercept,
                       non_negative,
                       max_iterations,
                       objective_epsilon,
                       beta_epsilon,
                       gradient_epsilon,
                       link,
                       rand_link,
                       startval,
                       calc_like,
                       HGLM,
                       prior,
                       lambda_min_ratio,
                       beta_constraints,
                       max_active_predictors,
                       obj_reg = obj_reg,
                       export_checkpoints_dir = export_checkpoints_dir,
                       balance_classes = balance_classes,
                       class_sampling_factor = class_sampling_factors,
                       max_after_balance_size = max_after_balance_size,
                       max_hit_ratio_k = max_hit_ratio_k,
                       max_runtime_secs = max_runtime_secs,
                       custom_metric_func = custom_metric_func)
    
      lambda_max <- model@model$lambda_best
    
      # Perform grid search on lambda, with logarithmic scale
      lambda_min <- lambda_max * lambda_min_ratio
      grid <- exp(seq(log(lambda_max), log(lambda_min), length.out = nlambdas))
      grid_list <- lapply(sapply(grid, list), list)
      hyper_parameters <- list(lambda = grid_list)
    
      result <- h2o.grid('glm',
                         x = x,
                         y = y,
                         training_frame = training_frame,
                         nfolds = nfolds,
                         family = family,
                         alpha = alpha,
                         ignore_const_cols = ignore_const_cols,
                         hyper_params = hyper_parameters,
                         seed = seed)
    }
    

    那么下面的函数可以用来根据误分类错误选择lambda:

    get_cv_means <- function(grid_results) {
      mean_errors <- lapply(grid_results@model_ids, function(id) {
        model <- h2o.getModel(id)
        lambda <- model@parameters$lambda
        err <- as.numeric(model@model$cross_validation_metrics_summary['err', 'mean'])
        data.frame(lambda = lambda, error = err)
      })
      dt <- data.table::rbindlist(mean_errors)
      data.table::setkey(dt, lambda)
      dt
    }
    

    下面是一个完整的例子,使用这些函数根据错误分类错误使用交叉验证来选择 lambda:

    h2o.init()
    path <- system.file("extdata", "prostate.csv", package= "h2o")
    h2o_df <- h2o.importFile(path)
    h2o_df$CAPSULE <- as.factor(h2o_df$CAPSULE)
    lambda_min_ratio <- 0.000001
    nlambdas <- 100
    nfolds <- 20
    
    result <- h2o.glm_custom(x = c("AGE", "RACE", "PSA", "GLEASON"),
                             y = "CAPSULE",
                             training_frame = h2o_df,
                             family = "binomial",
                             alpha = 1,
                             nfolds = nfolds,
                             lambda_min_ratio = lambda_min_ratio,
                             nlambdas = nlambdas,
                             early_stopping = TRUE)
    
    tbl <- get_cv_means(result)  
    

    给予:

    > head(tbl)
    lambda     error
    1: 2.222376e-07 0.2264758
    2: 2.555193e-07 0.2394541
    3: 2.937851e-07 0.2380508
    4: 3.377814e-07 0.2595451
    5: 3.883666e-07 0.2478443
    6: 4.465272e-07 0.2595603    
    

    哪些可以绘制,等等...

      ggplot() + geom_line(data = tbl[lambda < 0.00001], aes(x = lambda, y = error))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-07
      • 1970-01-01
      • 2020-01-18
      • 2018-05-31
      • 2021-07-19
      • 2014-02-18
      • 2021-09-10
      • 2011-06-06
      相关资源
      最近更新 更多