在 R 中为 h2o 模型打印 "pretty" 表
Print "pretty" tables for h2o models in R
R
有多个包可帮助从统计模型输出中打印 "pretty" 表 (LaTeX/HTML/TEXT) 并轻松比较替代模型规范的结果。
其中一些软件包是 apsrtable
、xtable
、memisc
、texreg
、outreg
和 stargazer
(有关示例,请参见这里:https://www.r-statistics.com/2013/01/stargazer-package-for-beautiful-latex-tables-from-r-statistical-models-output/).
是否有支持h2o
包模型的可比R
包?
这是两个带有 h2o
的简单 GLM 模型的示例,我喜欢将它们并排打印为 "beautiful" 表格。
# 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)
这是使用 texreg
包中的 screenreg()
的常规 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 xtable 包与 h2o 的 H2OTable 一起使用(或者 knitr 如果您使用 as.h2o(your_H2OTable)
将 H2OTable 转换为 H2OFrame),如果您从模型中提取它们输出。
例如,要从模型的系数中创建漂亮的 table,您需要先使用 model.output.1@model$coefficients_table
提取系数 table,然后您可以使用 xtable : xtable(prostate.glm@model$coefficients_table)
打印出 Latex 代码。
对于并排视图,在 knitr 或 xtable, or xtable and sweave
中有多个关于如何执行此操作的帖子
不,目前没有执行此操作的软件包。 broom 包还不支持 H2O 模型——那就太好了!也许这会在未来发生。一旦有办法使用 broom 或类似功能将 "tidy" 模型输出到 R data.frame 中,那么 xtable 等将很好地工作。
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 文本输出)。这三个函数用于将一些 cleaned-up 信息(系数、标准误差、置信区间、p-values、goodness-of-fit 统计数据、模型标签等)转换为各自的输出格式。这并不完美,还可以更灵活,但我认为目前它有很多关于定制的论据,包括 booktabs
和 dcolumn
支持。所以最大的挑战是首先获得 cleaned-up 模型信息。
这是通过向这三个函数中的任何一个提供 texreg
object 来完成的。 texreg
object 只是系数等的容器,使用 S4 class 正式定义。要创建 texreg
object,您可以使用构造函数 createTexreg
(如帮助页面中所述),它接受所有不同的信息片段作为参数,例如标准错误等。或者(更好)您可以使用 extract
函数从某些估计模型中提取这些信息,并 return a texreg
object 用于任何三个功能。你通常这样做的方式是将几个模型的列表交给 texreg
或 screenreg
等函数,这个函数将在内部调用 extract
来创建 texreg
objects然后处理来自那些objects的信息。
但是,仅将 extract
函数调用的输出保存到 object 中同样有效,可能操纵此 texreg
object,并且然后在被操纵的 object 上调用 texreg
函数,将其显示为 table。这允许在调整结果时有一定的灵活性。
早些时候,我提到过该包使用通用函数。这意味着 extract
函数在某种意义上是通用的,您可以为它注册适用于任意 classes 模型的方法。例如,如果extract
函数不知道如何处理h2o
object以及如何从这样的object中提取相关信息,你可以只写一个方法这样做并使用 extract
函数注册它。下面,我将逐步引导您完成此过程,希望人们能从这个详细的说明中学习并开始编写自己的扩展。 (注意:如果有人body开发了一个有用的方法,请e-mail我,我可以将它包含在下一个texreg
版本中。)还值得指出的是,包包含 70 多个 extract
方法示例,您可以将其用作模板。这些示例存储在文件 R/extract.R
.
中
识别 class 标签并设置 extract
方法
第一步是识别 object 的 class 名称。在您的示例中,class(model.output.1)
return 具有以下 class 标签:"H2OBinomialModel" 和 "h2o"。第一个标签是更具体的标签,第二个标签是更一般的标签。如果所有 h2o
模型 object 的结构都相似,那么为 h2o
object 编写一个扩展然后在方法中决定如何进行是有意义的与具体型号。由于我对 h2o
包几乎一无所知,在这种情况下,我更愿意从 H2OBinomialModel
object 的更具体的 extract
方法开始。如果我们愿意,可以稍后进行调整。
extract
方法的结构如下:您编写一个名为 extract.xyz
的函数(将 "xyz" 替换为 class 标签),至少有一个参数称为 model
,它接受模型 object(例如,您的示例中的 model.output.1
),将一些代码放在 body 中,从 model
object,使用 createTexreg
构造函数创建一个 texreg
object,然后 return 这个 object。这是一个空容器:
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
方法内传递给函数调用的自定义参数。
另请注意,函数定义 body 中的第一行将模型摘要保存在名为 s
的 object 中。这通常很有用,因为许多包编写者决定在摘要中以更简单的版本存储一些信息,因此通常应该与将模型及其摘要视为有用的信息来源。在某些情况下,可能需要查看相应包中摘要方法的实际定义,以了解在调用 summary
命令时如何计算摘要页面上显示的信息片段,因为并非所有 summary
方法存储 summary
object.
中显示的不同元素
在 H2OBinomialModel
object
中找到正确的信息
下一步是检查 object 并找到应在最终 table 中显示的所有详细信息。通过查看model.output.1
的输出,我猜测以下部分应该构成table底部的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
而下面的部分应该构成table中间的系数块:
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
object(或其摘要,如果适用)中找到所有这些内容。为此,有几个有用的命令。其中有str(model.output.1)
、names(summary(model.output.1))
等类似命令。
让我们从系数块开始。调用 str(model)
显示在 S4 object 中有一个名为 model
的插槽。我们可以通过调用model.output.1@model
来查看它的内容。结果是一个包含多个命名元素的列表,其中 coefficients_table
。所以我们可以通过调用model.output.1@model$coefficients_table
来访问系数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
据我所知,object 中没有存储标准错误或 p-values。如果我们希望这样做,我们可以编写一些额外的代码来计算它们,但在这里我们将重点关注作为模型输出的一部分随时提供的内容。
重要的是,我们不应覆盖 R
中的任何现有函数名称,例如 names
或 coef
。虽然这样做在技术上应该可行,因为代码稍后在一个函数中执行,但在尝试时很容易导致混淆,因此您最好避免这种情况。
接下来,我们需要找到 goodness-of-fit 统计信息。通过仔细检查 str(model.output.1)
的输出,我们看到 goodness-of-fit 统计信息包含在 model@model$training_metrics@metrics
下的几个槽中。让我们将它们保存到一些更容易访问的 object 中:
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
函数中。
但是,我们想让用户决定他或她更喜欢原始系数还是标准化系数,我们想让用户决定应该报告哪些 goodness-of-fit 统计数据,因此我们添加了各种逻辑函数 header 的参数,然后在函数内部使用 if-conditions 来检查我们是否应该在结果 texreg
object.
中嵌入相应的统计信息
在这种情况下,我们还删除了行 s <- summary(model)
,因为我们实际上不需要摘要中的任何类型的信息,因为我们在模型 object.[=141 中找到了我们需要的所有信息=]
完整的函数可能如下所示:
# 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)
}
对于 goodness-of-fit 块,您可以看到我首先创建了空向量,然后用额外的统计数据填充它们,前提是用户使用相应的参数打开了相应的统计数据。
gof.decimal
逻辑向量指示每个 GOF 统计量是否有小数位 (TRUE
) 或没有 (FALSE
,例如观察数)。
最后,需要将新函数注册为通用 extract
函数的方法。这是使用一个简单的命令完成的:
setMethod("extract", signature = className("H2OBinomialModel", "h2o"),
definition = extract.H2OBinomialModel)
这里,className
的第一个参数是class标签,第二个参数是定义class的包。
总而言之,编写自定义扩展只需要做两件事:1) 编写提取方法,以及 2) 注册该方法。也就是说,这段代码可以在运行时执行,不必插入任何包中。
但是,为了您的方便,我添加了H2OBinomialModel
方法到 texreg
版本 1.36.13,可在 CRAN 上获得。
请注意,此处提供的解决方案不适用于 texreg
的任何先前版本,因为先前版本无法处理既没有标准误差也没有置信区间的模型。在我看来,这是一个相当专业的设置,我还没有遇到过只提供估计而没有任何不确定性措施的软件包。我现在已经在 texreg
.
中解决了这个问题
尝试新的 extract
方法
在运行时执行函数定义和setMethod
命令后,可以使用以下命令创建table:
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 措施 and/or 使用标准化系数:
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
objects 中还提供以下插槽:
- se: 标准错误
- pvalues: p-values
- ci.low:置信区间的下限
- ci.up:置信区间的上限
- model.name:当前模型的标题
请注意,应使用置信区间或标准误差和 p-values,而不是两者。
操纵texreg
objects
除了将模型直接交给screenreg
、texreg
或htmlreg
函数外,还可以将提取的信息保存到texreg
object 并在显示或保存 table 之前对其进行操作。附加值是即使对 table 进行的复杂更改也可以通过这种方式轻松应用。例如,可以重命名系数或 GOF 统计数据、添加新行、重命名模型、修改值或更改系数或 GOF 统计数据的顺序。以下是如何做到这一点:首先,调用 extract
函数将信息保存到 texreg
object:
tr <- extract(model.output.1)
你可以通过调用tr
来显示texreg
object的内容,显示如下输出:
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
或者,这是 object 的结构,如 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)
现在您可以以任意方式操纵此 object,例如,添加 GOF 统计数据:
tr@gof.names <- c(tr@gof.names, "new statistic")
tr@gof <- c(tr@gof, 12)
tr@gof.decimal <- c(tr@gof.decimal, FALSE)
或者您可以更改系数的顺序:
tr@coef.names <- tr@coef.names[c(4, 1, 2, 3)]
tr@coef <- tr@coef[c(4, 1, 2, 3)]
当你完成操作后,你可以在调用时交出texreg
object而不是原来的模型,例如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 texreg
version 1.36.13 中包含了 H2OBinomialModel
方法,以及使用没有标准错误的模型的错误修复(例如这个)。
R
有多个包可帮助从统计模型输出中打印 "pretty" 表 (LaTeX/HTML/TEXT) 并轻松比较替代模型规范的结果。
其中一些软件包是 apsrtable
、xtable
、memisc
、texreg
、outreg
和 stargazer
(有关示例,请参见这里:https://www.r-statistics.com/2013/01/stargazer-package-for-beautiful-latex-tables-from-r-statistical-models-output/).
是否有支持h2o
包模型的可比R
包?
这是两个带有 h2o
的简单 GLM 模型的示例,我喜欢将它们并排打印为 "beautiful" 表格。
# 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)
这是使用 texreg
包中的 screenreg()
的常规 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 xtable 包与 h2o 的 H2OTable 一起使用(或者 knitr 如果您使用 as.h2o(your_H2OTable)
将 H2OTable 转换为 H2OFrame),如果您从模型中提取它们输出。
例如,要从模型的系数中创建漂亮的 table,您需要先使用 model.output.1@model$coefficients_table
提取系数 table,然后您可以使用 xtable : xtable(prostate.glm@model$coefficients_table)
打印出 Latex 代码。
对于并排视图,在 knitr 或 xtable, or xtable and sweave
中有多个关于如何执行此操作的帖子不,目前没有执行此操作的软件包。 broom 包还不支持 H2O 模型——那就太好了!也许这会在未来发生。一旦有办法使用 broom 或类似功能将 "tidy" 模型输出到 R data.frame 中,那么 xtable 等将很好地工作。
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 文本输出)。这三个函数用于将一些 cleaned-up 信息(系数、标准误差、置信区间、p-values、goodness-of-fit 统计数据、模型标签等)转换为各自的输出格式。这并不完美,还可以更灵活,但我认为目前它有很多关于定制的论据,包括 booktabs
和 dcolumn
支持。所以最大的挑战是首先获得 cleaned-up 模型信息。
这是通过向这三个函数中的任何一个提供 texreg
object 来完成的。 texreg
object 只是系数等的容器,使用 S4 class 正式定义。要创建 texreg
object,您可以使用构造函数 createTexreg
(如帮助页面中所述),它接受所有不同的信息片段作为参数,例如标准错误等。或者(更好)您可以使用 extract
函数从某些估计模型中提取这些信息,并 return a texreg
object 用于任何三个功能。你通常这样做的方式是将几个模型的列表交给 texreg
或 screenreg
等函数,这个函数将在内部调用 extract
来创建 texreg
objects然后处理来自那些objects的信息。
但是,仅将 extract
函数调用的输出保存到 object 中同样有效,可能操纵此 texreg
object,并且然后在被操纵的 object 上调用 texreg
函数,将其显示为 table。这允许在调整结果时有一定的灵活性。
早些时候,我提到过该包使用通用函数。这意味着 extract
函数在某种意义上是通用的,您可以为它注册适用于任意 classes 模型的方法。例如,如果extract
函数不知道如何处理h2o
object以及如何从这样的object中提取相关信息,你可以只写一个方法这样做并使用 extract
函数注册它。下面,我将逐步引导您完成此过程,希望人们能从这个详细的说明中学习并开始编写自己的扩展。 (注意:如果有人body开发了一个有用的方法,请e-mail我,我可以将它包含在下一个texreg
版本中。)还值得指出的是,包包含 70 多个 extract
方法示例,您可以将其用作模板。这些示例存储在文件 R/extract.R
.
识别 class 标签并设置 extract
方法
第一步是识别 object 的 class 名称。在您的示例中,class(model.output.1)
return 具有以下 class 标签:"H2OBinomialModel" 和 "h2o"。第一个标签是更具体的标签,第二个标签是更一般的标签。如果所有 h2o
模型 object 的结构都相似,那么为 h2o
object 编写一个扩展然后在方法中决定如何进行是有意义的与具体型号。由于我对 h2o
包几乎一无所知,在这种情况下,我更愿意从 H2OBinomialModel
object 的更具体的 extract
方法开始。如果我们愿意,可以稍后进行调整。
extract
方法的结构如下:您编写一个名为 extract.xyz
的函数(将 "xyz" 替换为 class 标签),至少有一个参数称为 model
,它接受模型 object(例如,您的示例中的 model.output.1
),将一些代码放在 body 中,从 model
object,使用 createTexreg
构造函数创建一个 texreg
object,然后 return 这个 object。这是一个空容器:
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
方法内传递给函数调用的自定义参数。
另请注意,函数定义 body 中的第一行将模型摘要保存在名为 s
的 object 中。这通常很有用,因为许多包编写者决定在摘要中以更简单的版本存储一些信息,因此通常应该与将模型及其摘要视为有用的信息来源。在某些情况下,可能需要查看相应包中摘要方法的实际定义,以了解在调用 summary
命令时如何计算摘要页面上显示的信息片段,因为并非所有 summary
方法存储 summary
object.
在 H2OBinomialModel
object
中找到正确的信息
下一步是检查 object 并找到应在最终 table 中显示的所有详细信息。通过查看model.output.1
的输出,我猜测以下部分应该构成table底部的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
而下面的部分应该构成table中间的系数块:
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
object(或其摘要,如果适用)中找到所有这些内容。为此,有几个有用的命令。其中有str(model.output.1)
、names(summary(model.output.1))
等类似命令。
让我们从系数块开始。调用 str(model)
显示在 S4 object 中有一个名为 model
的插槽。我们可以通过调用model.output.1@model
来查看它的内容。结果是一个包含多个命名元素的列表,其中 coefficients_table
。所以我们可以通过调用model.output.1@model$coefficients_table
来访问系数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
据我所知,object 中没有存储标准错误或 p-values。如果我们希望这样做,我们可以编写一些额外的代码来计算它们,但在这里我们将重点关注作为模型输出的一部分随时提供的内容。
重要的是,我们不应覆盖 R
中的任何现有函数名称,例如 names
或 coef
。虽然这样做在技术上应该可行,因为代码稍后在一个函数中执行,但在尝试时很容易导致混淆,因此您最好避免这种情况。
接下来,我们需要找到 goodness-of-fit 统计信息。通过仔细检查 str(model.output.1)
的输出,我们看到 goodness-of-fit 统计信息包含在 model@model$training_metrics@metrics
下的几个槽中。让我们将它们保存到一些更容易访问的 object 中:
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
函数中。
但是,我们想让用户决定他或她更喜欢原始系数还是标准化系数,我们想让用户决定应该报告哪些 goodness-of-fit 统计数据,因此我们添加了各种逻辑函数 header 的参数,然后在函数内部使用 if-conditions 来检查我们是否应该在结果 texreg
object.
在这种情况下,我们还删除了行 s <- summary(model)
,因为我们实际上不需要摘要中的任何类型的信息,因为我们在模型 object.[=141 中找到了我们需要的所有信息=]
完整的函数可能如下所示:
# 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)
}
对于 goodness-of-fit 块,您可以看到我首先创建了空向量,然后用额外的统计数据填充它们,前提是用户使用相应的参数打开了相应的统计数据。
gof.decimal
逻辑向量指示每个 GOF 统计量是否有小数位 (TRUE
) 或没有 (FALSE
,例如观察数)。
最后,需要将新函数注册为通用 extract
函数的方法。这是使用一个简单的命令完成的:
setMethod("extract", signature = className("H2OBinomialModel", "h2o"),
definition = extract.H2OBinomialModel)
这里,className
的第一个参数是class标签,第二个参数是定义class的包。
总而言之,编写自定义扩展只需要做两件事:1) 编写提取方法,以及 2) 注册该方法。也就是说,这段代码可以在运行时执行,不必插入任何包中。
但是,为了您的方便,我添加了H2OBinomialModel
方法到 texreg
版本 1.36.13,可在 CRAN 上获得。
请注意,此处提供的解决方案不适用于 texreg
的任何先前版本,因为先前版本无法处理既没有标准误差也没有置信区间的模型。在我看来,这是一个相当专业的设置,我还没有遇到过只提供估计而没有任何不确定性措施的软件包。我现在已经在 texreg
.
尝试新的 extract
方法
在运行时执行函数定义和setMethod
命令后,可以使用以下命令创建table:
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 措施 and/or 使用标准化系数:
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
objects 中还提供以下插槽:
- se: 标准错误
- pvalues: p-values
- ci.low:置信区间的下限
- ci.up:置信区间的上限
- model.name:当前模型的标题
请注意,应使用置信区间或标准误差和 p-values,而不是两者。
操纵texreg
objects
除了将模型直接交给screenreg
、texreg
或htmlreg
函数外,还可以将提取的信息保存到texreg
object 并在显示或保存 table 之前对其进行操作。附加值是即使对 table 进行的复杂更改也可以通过这种方式轻松应用。例如,可以重命名系数或 GOF 统计数据、添加新行、重命名模型、修改值或更改系数或 GOF 统计数据的顺序。以下是如何做到这一点:首先,调用 extract
函数将信息保存到 texreg
object:
tr <- extract(model.output.1)
你可以通过调用tr
来显示texreg
object的内容,显示如下输出:
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
或者,这是 object 的结构,如 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)
现在您可以以任意方式操纵此 object,例如,添加 GOF 统计数据:
tr@gof.names <- c(tr@gof.names, "new statistic")
tr@gof <- c(tr@gof, 12)
tr@gof.decimal <- c(tr@gof.decimal, FALSE)
或者您可以更改系数的顺序:
tr@coef.names <- tr@coef.names[c(4, 1, 2, 3)]
tr@coef <- tr@coef[c(4, 1, 2, 3)]
当你完成操作后,你可以在调用时交出texreg
object而不是原来的模型,例如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 texreg
version 1.36.13 中包含了 H2OBinomialModel
方法,以及使用没有标准错误的模型的错误修复(例如这个)。