R有多个软件包,可帮助从统计模型输出中打印“漂亮”表(LaTeX/HTML/TEXT),并轻松比较替代模型规范的结果。

其中一些软件包是apsrtablextablememisctexregoutregstargazer(示例请参见https://www.r-statistics.com/2013/01/stargazer-package-for-beautiful-latex-tables-from-r-statistical-models-output/)。

是否有支持R包模型的可比h2o包?

这是两个带有h2o的简单GLM模型的示例,我希望将它们彼此并排打印为“美丽”表。

# Load package and setup h2o
library(h2o)
localH2O <- h2o.init(ip = 'localhost', port = 54321, max_mem_size = '4g')

# Load data
prostatePath <- system.file("extdata", "prostate.csv", package = "h2o")
prostate.hex <- h2o.importFile(path = prostatePath, destination_frame = "prostate.hex")

# Run GLMs
model.output.1 <- h2o.glm(y = "CAPSULE", x = c("RACE","PSA","DCAPS"),
  training_frame = prostate.hex,family = "binomial", nfolds = 0,
  alpha = 0.5, lambda_search = FALSE)
model.output.2 <- h2o.glm(y = "CAPSULE", x = c("AGE","RACE","PSA","DCAPS"),
  training_frame = prostate.hex, family = "binomial", nfolds = 0,
  alpha = 0.5, lambda_search = FALSE)

这是使用screenreg()包中的texreg的常规GLM对象的外观:
library(data.table)
library(texreg)
d <- fread(prostatePath)
model.output.1.glm <- glm(CAPSULE ~ RACE + PSA + DCAPS, data=d)
model.output.2.glm <- glm(CAPSULE ~ AGE + RACE + PSA + DCAPS, data=d)
screenreg(list(model.output.1.glm, model.output.2.glm))

r - 在R中为H2O模型打印 “pretty”表-LMLPHP

最佳答案

texreg包作者在这里。 texreg基于通用函数,这意味着任何用户都可以为任意模型添加自定义extract方法,并使它们与texreg一起使用。我将在下面引导您完成此过程。我希望这个详细的展览会帮助过去曾经问过类似问题的其他人设计自己的texreg扩展名。

另请参见2013 paper in the Journal of Statistical Software中的第6节。但是,首先,我将描述texreg体系结构如何更一般地工作,以使您了解可能的情况。
texreg和通用extract函数

共有三个功能:texreg(用于LaTeX输出),htmlreg(用于HTML输出,在大多数使用场景下也可以由Word或Markdown解释)和screenreg(用于控制台中的ASCII文本输出)。这三个功能用于将一些清理后的信息(系数,标准误差,置信区间,p值,拟合优度统计信息,模型标签等)转换为相应的输出格式。这并不完美,甚至可以更加灵活,但是我认为目前有很多自定义参数,包括对booktabsdcolumn的支持。因此,最大的挑战是首先获得清理后的模型信息。

这可以通过为这三个函数中的任何一个提供texreg对象来完成。 texreg对象只是系数等的容器,并使用S4类正式定义。要创建texreg对象,您可以使用构造函数createTexreg(如帮助页面中所述),该函数接受所有不同的信息作为参数,例如标准错误等。或者(更好)您可以使用extract函数从一些估计的模型中提取这些信息,并返回texreg对象以与这三个函数中的任何一个一起使用。通常,您的方法是将几个模型的列表移交给texregscreenreg等函数,此函数将在内部调用extract来创建texreg对象,然后处理这些对象中的信息。

但是,将extract函数的调用输出保存到一个对象,可能会操纵该texreg对象,然后在被操纵的对象上调用texreg函数以将其显示为表同样有效。这样可以在调整结果时有一定的灵活性。

之前,我提到该程序包使用通用函数。这意味着extract函数是通用的,因为您可以为其注册适用于任意类模型的方法。例如,如果extract函数不知道如何处理h2o对象以及如何从此类对象中提取相关信息,则可以编写一种方法来完成该操作,然后将其注册到extract函数中。下面,我将逐步引导您完成该过程,希望人们可以从这个详细的博览会中学到东西并开始编写自己的扩展。 (注意:如果有人开发了一种有用的方法,请给我发送电子邮件,我可以将其包含在下一个texreg版本中。)还值得指出的是,该包的源文件包含70多个extract方法的示例,您可以使用这些示例可以用作模板。这些示例存储在文件R/extract.R中。

标识类标签并设置extract方法

第一步是识别对象的类名称。在您的示例中,class(model.output.1)返回以下类标签:“H2OBinomialModel”和“h2o”。第一个标签是更具体的标签,第二个标签是更一般的标签。如果所有h2o模型对象的结构都相似,则有必要编写h2o对象的扩展名,然后在方法内决定如何继续使用特定模型。由于我对h2o包几乎一无所知,因此我更喜欢在这种情况下以针对extract对象的更特定的H2OBinomialModel方法开始。如果我们希望以后可以进行调整。
extract方法的结构如下:您编写了一个名为extract.xyz的函数(用类标签替换“xyz”),至少有一个名为model的参数,该参数接受模型对象(例如,示例中的model.output.1),并在其中添加了一些代码从model对象提取相关信息的主体,使用texreg构造函数创建createTexreg对象,然后返回此对象。这是一个空容器:

extract.H2OBinomialModel <- function(model, ...) {
  s <- summary(model)

  # extract information from model and summary object here

  # then create and return a texreg object (replace NULL with actual values):
  tr <- createTexreg(
    coef.names = NULL,    # character vector of coefficient labels
    coef = NULL,          # numeric vector with coefficients
    se = NULL,            # numeric vector with standard error values
    pvalues = NULL,       # numeric vector with p-values
    gof.names = NULL,     # character vector with goodness-of-fit labels
    gof = NULL,           # numeric vector of goodness-of-fit statistics
    gof.decimal = NULL    # logical vector: GOF statistic has decimal points?
  )
  return(tr)
}

请注意,函数定义还包含...参数,该参数可用于应传递给extract方法内的函数调用的自定义参数。

还要注意,函数定义主体中的第一行将模型摘要保存在名为s的对象中。这通常很有用,因为许多软件包编写者决定将一些信息存储在摘要中的更简单版本中,因此通常应将模型及其摘要都视为有用的信息源。在某些情况下,可能需要查看相应程序包中summary方法的实际定义,以找出调用summary命令时如何计算显示在摘要页面上的信息,因为并非所有summary方法都存储不同的方法。显示在summary对象中的元素。

H2OBinomialModel对象中找到正确的信息

下一步是检查对象并找到最终表中应显示的所有详细信息。通过查看model.output.1的输出,我猜想以下部分应该构成表底部的GOF块:
MSE:  0.202947
R^2:  0.1562137
LogLoss:  0.5920097
Mean Per-Class Error:  0.3612191
AUC:  0.7185655
Gini:  0.4371311
Null Deviance:  512.2888
Residual Deviance:  449.9274
AIC:  457.9274

以下部分可能会构成表格中间的系数块:
Coefficients: glm coefficients
      names coefficients standardized_coefficients
1 Intercept    -1.835223                 -0.336428
2      RACE    -0.625222                 -0.193052
3     DCAPS     1.314428                  0.408336
4       PSA     0.046861                  0.937107

在许多情况下,摘要包含相关信息,但是在这里打印模型可以满足我们的需求。我们将需要在model.output.1对象(或其适用的摘要)中找到所有这些内容。为此,有几个有用的命令。其中包括str(model.output.1)names(summary(model.output.1))和类似的命令。

让我们从系数块开始。调用str(model)将显示S4对象中存在一个名为model的插槽。我们可以通过调用model.output.1@model来查看其内容。结果是一个包含几个命名元素的列表,其中包括coefficients_table。因此,我们可以通过调用model.output.1@model$coefficients_table来访问系数表。结果是一个数据框,我们可以使用$运算符访问其列。特别是,我们需要名称和系数。这里有两种类型的系数,标准化的和非标准化的,以后我们可以在我们的提取方法中添加一个参数,让用户决定他或她想要什么。这是我们提取系数及其标签的方法:
coefnames <- model.output.1@model$coefficients_table$names
coefs <- model.output.1@model$coefficients_table$coefficients
coefs.std <- model.output.1@model$coefficients_table$standardized_coefficients

据我所知,该对象中没有存储任何标准误差或p值。如果我们愿意,我们可以编写一些其他代码来计算它们,但是在这里,我们将集中于那些作为模型输出的一部分容易提供的东西。

重要的是,我们不应覆盖R中的任何现有函数名,例如namescoef。尽管这样做在技术上应该可行,因为代码是在以后的函数中执行的,但是在尝试时很容易导致混淆,因此您最好避免这种情况。

接下来,我们需要找到拟合优度统计信息。通过仔细检查str(model.output.1)的输出,我们看到拟合优度统计信息包含在model@model$training_metrics@metrics下的几个插槽中。让我们将它们保存到一些更易于访问的对象中:
mse <- model.output.1@model$training_metrics@metrics$MSE
r2 <- model.output.1@model$training_metrics@metrics$r2
logloss <- model.output.1@model$training_metrics@metrics$logloss
mpce <- model.output.1@model$training_metrics@metrics$mean_per_class_error
auc <- model.output.1@model$training_metrics@metrics$AUC
gini <- model.output.1@model$training_metrics@metrics$Gini
nulldev <- model.output.1@model$training_metrics@metrics$null_deviance
resdev <- model.output.1@model$training_metrics@metrics$residual_deviance
aic <- model.output.1@model$training_metrics@metrics$AIC

在某些情况下,但不是在这里,软件包的作者为通用函数编写方法,这些方法可用于提取一些常用信息,例如观察数(nobs(model)),AIC(AIC(model)),BIC(BIC(model)),偏差(deviance(model)) ,或对数似然(logLik(model)[[1]])。因此,您可能首先要尝试这些。但是h2o包似乎没有提供这种方便的方法。

将信息添加到extract.H2OBinomialModel函数

现在,我们已经找到了所需的所有信息,可以将它们添加到上面定义的extract.H2OBinomialModel函数中。

但是,我们希望让用户决定他还是她更喜欢原始系数还是标准系数,并且我们希望让用户决定应该报告哪个拟合优度统计信息,因此我们向函数头添加了各种逻辑参数。然后在函数内部使用if-conditions来检查是否应将相应的统计信息嵌入到生成的texreg对象中。

在这种情况下,我们还删除了s <- summary(model)行,这是因为实际上我们不需要摘要中的任何信息,因为我们在模型对象中找到了所需的一切。

完整的功能可能如下所示:
# extension for H2OBinomialModel objects (h2o package)
extract.H2OBinomialModel <- function(model, standardized = FALSE,
      include.mse = TRUE, include.rsquared = TRUE, include.logloss = TRUE,
      include.meanerror = TRUE, include.auc = TRUE, include.gini = TRUE,
      include.deviance = TRUE, include.aic = TRUE, ...) {

  # extract coefficient table from model:
  coefnames <- model@model$coefficients_table$names
  if (standardized == TRUE) {
    coefs <- model@model$coefficients_table$standardized_coefficients
  } else {
    coefs <- model@model$coefficients_table$coefficients
  }

  # create empty GOF vectors and subsequently add GOF statistics from model:
  gof <- numeric()
  gof.names <- character()
  gof.decimal <- logical()
  if (include.mse == TRUE) {
    mse <- model@model$training_metrics@metrics$MSE
    gof <- c(gof, mse)
    gof.names <- c(gof.names, "MSE")
    gof.decimal <- c(gof.decimal, TRUE)
  }
  if (include.rsquared == TRUE) {
    r2 <- model@model$training_metrics@metrics$r2
    gof <- c(gof, r2)
    gof.names <- c(gof.names, "R^2")
    gof.decimal <- c(gof.decimal, TRUE)
  }
  if (include.logloss == TRUE) {
    logloss <- model@model$training_metrics@metrics$logloss
    gof <- c(gof, logloss)
    gof.names <- c(gof.names, "LogLoss")
    gof.decimal <- c(gof.decimal, TRUE)
  }
  if (include.meanerror == TRUE) {
    mpce <- model@model$training_metrics@metrics$mean_per_class_error
    gof <- c(gof, mpce)
    gof.names <- c(gof.names, "Mean Per-Class Error")
    gof.decimal <- c(gof.decimal, TRUE)
  }
  if (include.auc == TRUE) {
    auc <- model@model$training_metrics@metrics$AUC
    gof <- c(gof, auc)
    gof.names <- c(gof.names, "AUC")
    gof.decimal <- c(gof.decimal, TRUE)
  }
  if (include.gini == TRUE) {
    gini <- model@model$training_metrics@metrics$Gini
    gof <- c(gof, gini)
    gof.names <- c(gof.names, "Gini")
    gof.decimal <- c(gof.decimal, TRUE)
  }
  if (include.deviance == TRUE) {
    nulldev <- model@model$training_metrics@metrics$null_deviance
    resdev <- model@model$training_metrics@metrics$residual_deviance
    gof <- c(gof, nulldev, resdev)
    gof.names <- c(gof.names, "Null Deviance", "Residual Deviance")
    gof.decimal <- c(gof.decimal, TRUE, TRUE)
  }
  if (include.aic == TRUE) {
    aic <- model@model$training_metrics@metrics$AIC
    gof <- c(gof, aic)
    gof.names <- c(gof.names, "AIC")
    gof.decimal <- c(gof.decimal, TRUE)
  }

  # create texreg object:
  tr <- createTexreg(
    coef.names = coefnames,
    coef = coefs,
    gof.names = gof.names,
    gof = gof,
    gof.decimal = gof.decimal
  )
  return(tr)
}

对于拟合优度块,您可以看到我首先创建了空向量,然后在填充了其他统计信息的情况下填充了这些向量,前提是用户使用相应的参数打开了相应的统计信息。
gof.decimal逻辑向量为每个GOF统计信息指示其是否具有小数位(TRUE)(例如,观察数中为FALSE)。

最后,需要将新功能注册为通用extract功能的方法。这是使用一个简单的命令完成的:
setMethod("extract", signature = className("H2OBinomialModel", "h2o"),
definition = extract.H2OBinomialModel)

在此,className的第一个参数是类标签,第二个参数是在其中定义类的包。

总结起来,编写自定义扩展名仅需要做两件事:1)编写提取方法,以及2)注册该方法。也就是说,此代码可以在运行时执行,而不必插入任何包中。

但是,为了方便起见,我在H2OBinomialModel版本1.36.13中添加了texreg方法,该方法在CRAN上可用。

请注意,此处提供的解决方案不适用于任何以前的texreg版本,因为以前的版本无法处理既没有标准错误也没有置信区间的模型。我认为这是一个相当专业的设置,我没有遇到过一个仅提供估计值而没有任何不确定性度量的程序包。我现在已经在texreg中修复了这个问题。

试用新的extract方法

一旦在运行时执行了函数定义和setMethod命令,就可以使用以下命令创建表:
screenreg(list(model.output.1, model.output.2), custom.note = "")

这是输出:
======================================
                      Model 1  Model 2
--------------------------------------
Intercept              -1.84    -1.11
RACE                   -0.63    -0.62
DCAPS                   1.31     1.31
PSA                     0.05     0.05
AGE                             -0.01
--------------------------------------
MSE                     0.20     0.20
R^2                     0.16     0.16
LogLoss                 0.59     0.59
Mean Per-Class Error    0.36     0.38
AUC                     0.72     0.72
Gini                    0.44     0.44
Null Deviance         512.29   512.29
Residual Deviance     449.93   449.51
AIC                   457.93   459.51
======================================

此处的custom.note = ""参数是有意义的,因为我们不需要重要的图例,因为模型没有报告任何不确定性度量。

也可以抑制某些GOF度量和/或使用标准化系数:
screenreg(list(model.output.1, model.output.2), custom.note = "",
    include.deviance = FALSE, include.auc = FALSE, standardized = TRUE)

结果:
======================================
                      Model 1  Model 2
--------------------------------------
Intercept              -0.34    -0.34
RACE                   -0.19    -0.19
DCAPS                   0.41     0.41
PSA                     0.94     0.94
AGE                             -0.07
--------------------------------------
MSE                     0.20     0.20
R^2                     0.16     0.16
LogLoss                 0.59     0.59
Mean Per-Class Error    0.36     0.38
Gini                    0.44     0.44
AIC                   457.93   459.51
======================================

可以与createTexreg一起使用的其他插槽
createTexreg构造函数在任何extract方法中调用。上面的示例显示了一些简单的信息。除了示例中包含的详细信息之外,texreg对象中还提供了以下插槽:
  • se:标准错误
  • pvalues:p值
  • ci.low:置信区间
  • 的下限
  • ci.up:置信区间
  • 的上限
  • model.name:当前模型的标题

  • 请注意,应该使用置信区间或标准误差和p值,而不要同时使用两者。

    操作texreg对象

    除了将模型直接移交给screenregtexreghtmlreg函数之外,还可以先将提取的信息保存到texreg对象,然后在显示或保存表之前对其进行操作。附加值是,即使对表进行复杂的更改也很容易以这种方式应用。例如,可以重命名系数或GOF统计信息,添加新行,重命名模型,修改值或更改系数或GOF统计信息的顺序。您可以按照以下方法进行操作:首先,调用extract函数将信息保存到texreg对象:
    tr <- extract(model.output.1)
    

    您可以仅通过调用texreg来显示tr对象的内容,这将显示以下输出:
    No standard errors and p-values were defined for this texreg object.
    
                    coef.
    Intercept -1.83522343
    RACE      -0.62522179
    DCAPS      1.31442834
    PSA        0.04686106
    
                                 GOF dec. places
    MSE                    0.2029470        TRUE
    R^2                    0.1562137        TRUE
    LogLoss                0.5920097        TRUE
    Mean Per-Class Error   0.3612191        TRUE
    AUC                    0.7185655        TRUE
    Gini                   0.4371311        TRUE
    Null Deviance        512.2888402        TRUE
    Residual Deviance    449.9273825        TRUE
    AIC                  457.9273825        TRUE
    

    另外,这是对象的结构,如str(tr)所示:
    Formal class 'texreg' [package "texreg"] with 10 slots
      ..@ coef.names : chr [1:4] "Intercept" "RACE" "DCAPS" "PSA"
      ..@ coef       : num [1:4] -1.8352 -0.6252 1.3144 0.0469
      ..@ se         : num(0)
      ..@ pvalues    : num(0)
      ..@ ci.low     : num(0)
      ..@ ci.up      : num(0)
      ..@ gof.names  : chr [1:9] "MSE" "R^2" "LogLoss" "Mean Per-Class Error" ...
      ..@ gof        : num [1:9] 0.203 0.156 0.592 0.361 0.719 ...
      ..@ gof.decimal: logi [1:9] TRUE TRUE TRUE TRUE TRUE TRUE ...
      ..@ model.name : chr(0)
    

    现在,您可以通过任意方式操作此对象,例如,添加GOF统计信息:
    [email protected] <- c([email protected], "new statistic")
    tr@gof <- c(tr@gof, 12)
    [email protected] <- c([email protected], FALSE)
    

    或者,您可以更改系数的顺序:
    [email protected] <- [email protected][c(4, 1, 2, 3)]
    tr@coef <- tr@coef[c(4, 1, 2, 3)]
    

    完成操作后,可以在调用时移交texreg对象而不是原始模型,例如screenreg:
    screenreg(list(tr, model.output.2), custom.note = "")
    

    新结果将如下所示:
    ======================================
                          Model 1  Model 2
    --------------------------------------
    PSA                     0.05     0.05
    Intercept              -1.84    -1.11
    RACE                   -0.63    -0.62
    DCAPS                   1.31     1.31
    AGE                             -0.01
    --------------------------------------
    MSE                     0.20     0.20
    R^2                     0.16     0.16
    LogLoss                 0.59     0.59
    Mean Per-Class Error    0.36     0.38
    AUC                     0.72     0.72
    Gini                    0.44     0.44
    Null Deviance         512.29   512.29
    Residual Deviance     449.93   449.51
    AIC                   457.93   459.51
    new statistic          12
    ======================================
    

    TL; DR
    texreg可以由用户自定义。只需编写上面显示的提取方法,然后使用setMethods调用进行注册即可。我已经在latest H2OBinomialModel version 1.36.13中包括了texreg方法,以及一个用于修正使用没有标准错误(例如此错误)的模型的错误修正。

    关于r - 在R中为H2O模型打印 “pretty”表,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38894044/

    10-12 17:19