r h2o stargazer texreg

Imprima tablas "bonitas" para modelos h2o en R



stargazer texreg (3)

Existen múltiples paquetes para R que ayudan a imprimir tablas "bonitas" (LaTeX / HTML / TEXT) desde la salida de modelos estadísticos Y para comparar fácilmente los resultados de especificaciones de modelos alternativos.

Algunos de estos paquetes son apsrtable , xtable , memisc , texreg , outreg y stargazer (para ver ejemplos, consulte aquí: https://www.r-statistics.com/2013/01/stargazer-package-for-beautiful-latex-tables-from-r-statistical-models-output/ ).

¿Existe algún paquete R comparable que admita los modelos del paquete h2o ?

Aquí hay un ejemplo de dos modelos GLM simples con h2o que me gusta imprimir uno al lado del otro como tablas "hermosas".

# 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)

Así es como se vería con un objeto GLM normal usando screenreg() del paquete texreg :

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))


No, no hay un paquete que haga esto actualmente. El paquete de broom aún no es compatible con los modelos H2O, ¡eso sería genial! Tal vez eso podría suceder en el futuro. Una vez que haya una manera de "ordenar" la salida del modelo en un marco de datos R usando una escoba o una funcionalidad similar, entonces xtable, etc. funcionará bien.


puede usar el paquete R xtable con H2OTable de h2o (o knitr si convierte el H2OTable en un H2OFrame usando as.h2o(your_H2OTable) ), si los extrae de la salida del modelo.

por ejemplo, para crear una hermosa tabla a partir de los coeficientes de un modelo, primero deberá extraer la tabla de coeficientes con model.output.1@model$coefficients_table , luego puede usar xtable: xtable(prostate.glm@model$coefficients_table) para imprimir El código de látex.

para vistas de lado a lado, hay múltiples publicaciones sobre cómo hacer esto en knitr o xtable , o xtable y sweave


texreg autor del paquete texreg aquí. texreg se basa en funciones genéricas, lo que significa que cualquier usuario puede agregar métodos de extract personalizados para modelos arbitrarios y hacer que funcionen con texreg . Te guiaré a través de esto a continuación. Espero que esta exposición detallada ayude a otras personas que han hecho preguntas similares en el pasado a diseñar sus propias extensiones de texreg .

Vea también la Sección 6 en el artículo de 2013 en el Journal of Statistical Software para otro ejemplo. Primero, sin embargo, describiré cómo funciona la arquitectura texreg más general para darle una idea de lo que es posible.

texreg y la función de extract genérico

Hay tres funciones: texreg (para salida LaTeX), htmlreg (para salida HTML, que también puede ser interpretada por Word o Markdown en la mayoría de los escenarios de uso) y screenreg (para salida de texto ASCII en la consola). Estas tres funciones sirven para convertir información limpiada (coeficientes, errores estándar, intervalos de confianza, valores p, estadísticas de bondad de ajuste, etiquetas de modelo, etc.) en los formatos de salida respectivos. Esto no es perfecto y podría ser aún más flexible, pero creo que tiene bastantes argumentos para la personalización en este punto, incluidas cosas como las booktabs y el soporte de dcolumn . Entonces, el gran desafío es, en primer lugar, obtener información del modelo limpiada.

Esto se hace proporcionando un objeto texreg a cualquiera de estas tres funciones. Un objeto texreg es solo un contenedor para coeficientes, etc. y se define formalmente usando una clase S4. Para crear un objeto texreg , puede usar la función constructora createTexreg (como se documenta en las páginas de ayuda), que acepta todos los diferentes elementos de información como argumentos, como los errores estándar, etc. O (mejor) puede usar el extract función para extraer esos datos de algún modelo estimado y devolver un objeto texreg para usar con cualquiera de las tres funciones. La forma en que normalmente hace esto es simplemente entregando una lista de varios modelos a la función texreg o screenreg etc., y esta función llamará internamente a extract para crear objetos texreg y luego procesará la información de esos objetos.

Sin embargo, es igualmente válido simplemente guardar la salida de una llamada de la función de extract en un objeto, posiblemente manipular este objeto texreg y luego llamar a la función texreg en el objeto manipulado para mostrarlo como una tabla. Esto permite cierta flexibilidad para ajustar los resultados.

Anteriormente, mencioné que el paquete usa funciones genéricas. Esto significa que la función de extract es genérica en el sentido de que puede registrar métodos para ella que funcionan con clases arbitrarias de modelos. Por ejemplo, si la función de extract no sabe cómo manejar objetos h2o y cómo extraer la información relevante de dicho objeto, simplemente puede escribir un método para hacerlo y registrarlo con la función de extract . A continuación, lo guiaré paso a paso con la esperanza de que la gente aprenda de esta exposición detallada y comience a escribir sus propias extensiones. (Nota: si alguien desarrolla un método útil, envíeme un correo electrónico y puedo incluirlo en la próxima versión de texreg ). También vale la pena señalar que los archivos fuente del paquete contienen más de 70 ejemplos de métodos de extract que puede puede usar como plantillas. Estos ejemplos se almacenan en el archivo R/extract.R .

Identificar la etiqueta de clase y configurar un método de extract

El primer paso es identificar el nombre de la clase del objeto. En su ejemplo, la class(model.output.1) devuelve las siguientes etiquetas de clase: "H2OBinomialModel" y "h2o". La primera etiqueta es la más específica, y la segunda etiqueta es la más general. Si todos los objetos del modelo h2o están estructurados de manera similar, tendrá sentido escribir una extensión para los objetos h2o y luego decidir dentro del método cómo proceder con el modelo específico. Como prácticamente no sé nada sobre el paquete h2o , prefiero comenzar con un método de extract más específico para los objetos H2OBinomialModel en este caso. Se puede ajustar más adelante si deseamos hacerlo.

extract métodos de extract están estructurados de la siguiente manera: escribe una función llamada extract.xyz (reemplace "xyz" por la etiqueta de clase), tiene al menos un argumento llamado model , que acepta el objeto modelo (por ejemplo, model.output.1 en su ejemplo ), coloque un código en el cuerpo que extraiga la información relevante del objeto model , cree un objeto texreg utilizando el constructor createTexreg y devuelva este objeto. Aquí hay un contenedor vacío:

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) }

Tenga en cuenta que la definición de la función también contiene el argumento ... , que se puede utilizar para argumentos personalizados que se deben entregar a las llamadas a funciones dentro del método de extract .

Tenga en cuenta también que la primera línea en el cuerpo de la definición de la función guarda el resumen del modelo en un objeto llamado s . Esto suele ser útil porque muchos redactores de paquetes deciden almacenar parte de la información en una versión más simple en el resumen, por lo que generalmente se debe considerar ambos, el modelo y su resumen, como fuentes útiles de información. En algunos casos, es posible que tenga que mirar la definición real del método de resumen en el paquete respectivo para averiguar cómo se calculan los datos que se muestran en la página de resumen cuando se llama al comando de summary porque no todos los métodos de summary almacenan los diferentes elementos que se muestran en el objeto de summary .

Localizar la información correcta en un objeto H2OBinomialModel

El siguiente paso es examinar el objeto y localizar todos los detalles que deberían mostrarse en la tabla final. Al observar la salida de model.output.1 , supongo que la siguiente parte debería constituir el bloque GOF en la parte inferior de la tabla:

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

Y la siguiente parte probablemente debería constituir el bloque de coeficientes en el medio de la tabla:

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

En muchos casos, el resumen contiene la información relevante, pero aquí imprimir el modelo produce lo que necesitamos. Necesitaremos ubicar todo esto en el objeto model.output.1 (o su resumen, si corresponde). Para hacer eso, hay varios comandos útiles. Entre ellos se encuentran str(model.output.1) , names(summary(model.output.1)) y comandos similares.

Comencemos con el bloque de coeficientes. Llamar a str(model) revela que hay una ranura llamada model en el objeto S4. Podemos ver su contenido llamando a model.output.1@model . El resultado es una lista con varios elementos con nombre, entre ellos coefficients_table . Entonces podemos acceder a la tabla de coeficientes llamando a model.output.1@model$coefficients_table . El resultado es un marco de datos cuyas columnas podemos acceder utilizando el operador $ . En particular, necesitamos los nombres y los coeficientes. Aquí hay dos tipos de coeficientes, estandarizados y no estandarizados, y podemos agregar un argumento a nuestro método de extracción más adelante para permitir que el usuario decida lo que quiere. Así es como extraemos los coeficientes y sus etiquetas:

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

Hasta donde puedo ver, no hay errores estándar o valores p almacenados en el objeto. Podríamos escribir un código adicional para calcularlos si quisiéramos hacerlo, pero aquí nos centraremos en las cosas que se proporcionan fácilmente como parte de la salida del modelo.

Es importante que no sobrescribamos ningún nombre de función existente en R , como names o coef . Si bien esto debería funcionar técnicamente porque el código se ejecuta dentro de una función más adelante, esto puede conducir fácilmente a la confusión al probar cosas, por lo que es mejor evitarlo.

Luego, necesitamos localizar las estadísticas de bondad de ajuste. Al examinar la salida de str(model.output.1) cuidadosamente, vemos que las estadísticas de bondad de ajuste están contenidas en varios espacios bajo model@model$training_metrics@metrics . Vamos a guardarlos en algunos objetos que son más fáciles de acceder:

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

En algunos casos, pero no aquí, el autor de un paquete escribe métodos para funciones genéricas que se pueden usar para extraer información común como el número de observaciones ( nobs(model) ), AIC ( AIC(model) ), BIC ( BIC(model) ), desviación ( deviance(model) ) o la probabilidad de registro ( logLik(model)[[1]] ). Entonces, estas son cosas que quizás quieras probar primero; pero el paquete h2o no parece ofrecer tales métodos convenientes.

Agregar la información a la función extract.H2OBinomialModel

Ahora que hemos localizado todos los datos que necesitamos, podemos agregarlos al extract.H2OBinomialModel Función extract.H2OBinomialModel que definimos anteriormente.

Sin embargo, nos gustaría dejar que el usuario decida si prefiere coeficientes brutos o estandarizados, y nos gustaría que el usuario decida qué estadísticas de bondad de ajuste se deben informar, por lo que agregamos varios argumentos lógicos al encabezado de la función y luego use las condiciones if dentro de la función para verificar si debemos incrustar las estadísticas respectivas en el objeto texreg resultante.

También eliminamos la línea s <- summary(model) en este caso porque en realidad no necesitamos ningún tipo de información del resumen ya que encontramos todo lo que necesitamos en el objeto del modelo.

La función completa puede verse así:

# 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) }

Para el bloque de bondad de ajuste, puede ver que primero creé vectores vacíos y luego los rellené con estadísticas adicionales siempre que el usuario activara la estadística respectiva utilizando el argumento respectivo.

El vector lógico gof.decimal indica para cada estadística GOF si tiene decimales ( TRUE ) o no ( FALSE , como en el número de observaciones, por ejemplo).

Finalmente, la nueva función debe registrarse como método para la función de extract genérica. Esto se hace usando un comando simple:

setMethod("extract", signature = className("H2OBinomialModel", "h2o"), definition = extract.H2OBinomialModel)

Aquí, el primer argumento de className es la etiqueta de clase, y el segundo es el paquete en el que se define la clase.

En resumen, las dos únicas cosas que deben hacerse para escribir una extensión personalizada son 1) escribir un método de extracción y 2) registrar el método. Es decir, este código puede ejecutarse en tiempo de ejecución y no tiene que insertarse en ningún paquete.

Sin embargo, para su comodidad, he agregado el método texreg versión 1.36.13 de texreg, que está disponible en CRAN.

Tenga en cuenta que la solución presentada aquí no funciona con ninguna versión anterior de texreg porque las versiones anteriores no podían tratar con modelos que no tenían errores estándar ni intervalos de confianza. Esta es una configuración bastante especializada en mi opinión, y no había encontrado un paquete que simplemente proporciona las estimaciones sin ninguna medida de incertidumbre. Ahora he arreglado esto en texreg .

Probar el nuevo método de extract

Una vez que la definición de la función y el comando setMethod se han ejecutado en tiempo de ejecución, se puede usar el siguiente comando para crear una tabla:

screenreg(list(model.output.1, model.output.2), custom.note = "")

Esta es la salida:

====================================== 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 ======================================

El custom.note = "" tiene sentido aquí porque no queremos una leyenda de importancia ya que los modelos no informan ninguna medida de incertidumbre.

También es posible suprimir algunas de las medidas GOF y / o utilizar coeficientes estandarizados:

screenreg(list(model.output.1, model.output.2), custom.note = "", include.deviance = FALSE, include.auc = FALSE, standardized = TRUE)

El resultado:

====================================== 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 ======================================

Otras ranuras que se pueden usar con createTexreg

La función constructora createTexreg se llama dentro de cualquier método de extract . El ejemplo anterior muestra algunas piezas simples de información. Además de los detalles contenidos en el ejemplo, las siguientes ranuras están disponibles en objetos texreg :

  • se: errores estándar
  • valores: los valores p
  • ci.low: límite inferior de un intervalo de confianza
  • ci.up: límite superior de un intervalo de confianza
  • model.name: el título del modelo actual

Tenga en cuenta que deben usarse intervalos de confianza o errores estándar y valores p, no ambos.

Manipulando objetos texreg

Además de entregar los modelos a las screenreg , texreg o htmlreg directamente, es posible guardar primero la información extraída en un objeto texreg y manipularla antes de mostrar o guardar la tabla. El valor agregado es que incluso los cambios complejos en una tabla son fáciles de aplicar de esta manera. Por ejemplo, es posible cambiar el nombre de los coeficientes o las estadísticas GOF, agregar nuevas filas, cambiar el nombre de un modelo, modificar los valores o cambiar el orden de los coeficientes o las estadísticas GOF. Así es como puede hacer eso: Primero, llame a la función de extract para guardar la información en un objeto texreg :

tr <- extract(model.output.1)

Puede mostrar el contenido del objeto texreg simplemente llamando a tr , que muestra el siguiente resultado:

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

Alternativamente, esta es la estructura del objeto como se muestra por 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)

Ahora puede manipular este objeto de manera arbitraria, por ejemplo, agregar una estadística GOF:

[email protected] <- c([email protected], "new statistic") tr@gof <- c(tr@gof, 12) [email protected] <- c([email protected], FALSE)

O puede cambiar el orden de los coeficientes:

[email protected] <- [email protected][c(4, 1, 2, 3)] tr@coef <- tr@coef[c(4, 1, 2, 3)]

Cuando haya terminado con las manipulaciones, puede entregar el objeto texreg lugar del modelo original cuando llame, por ejemplo, screenreg :

screenreg(list(tr, model.output.2), custom.note = "")

El nuevo resultado se verá así:

====================================== 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 puede ser personalizado por los usuarios. Simplemente escriba un método de extracción como el que se muestra arriba y regístrelo usando una llamada setMethods . He incluido el método H2OBinomialModel en la última versión de texreg 1.36.13, junto con una corrección de errores para usar modelos sin errores estándar (como este).