Распечатать "красивые" таблицы для моделей H2O в R

Есть несколько пакетов для R которые помогают печатать "красивые" таблицы (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/).

Есть ли сопоставимые R пакет, который поддерживает модели из h2o пакет?

Вот пример двух простых моделей GLM с h2o которые я люблю печатать рядом друг с другом как "красивые" столы.

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

Вот как это будет выглядеть с обычным объектом GLM, использующим screenreg() от 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))

введите описание изображения здесь

3 ответа

Решение

texreg Автор пакета здесь. texreg основан на общих функциях, что означает, что любой пользователь может добавить пользовательский extract методы для произвольных моделей и заставить их работать с texreg, Я проведу вас через это ниже. Я надеюсь, что эта подробная экспозиция поможет другим людям, которые задавали подобные вопросы в прошлом, разработать свои собственные texreg расширения.

См. Также раздел 6 в статье 2013 года в журнале статистического программного обеспечения для другого примера. Однако сначала я опишу, как texreg архитектура работает более широко, чтобы дать вам представление о том, что возможно.

texreg и общий extract функция

Есть три функции: texreg (для вывода LaTeX), htmlreg (для вывода HTML, который также может интерпретироваться Word или Markdown в большинстве сценариев использования), и screenreg (для вывода текста ASCII в консоли). Эти три функции служат для преобразования некоторой очищенной информации (коэффициенты, стандартные ошибки, доверительные интервалы, p-значения, статистика соответствия), метки модели и т. Д.) В соответствующие выходные форматы. Это не идеально и может быть даже более гибким, но я думаю, что на данный момент у него довольно много аргументов для настройки, включая такие вещи, как booktabs а также dcolumn служба поддержки. Таким образом, большая проблема заключается в том, чтобы сначала получить очищенную информацию о модели.

Это делается путем предоставления texreg возражать против любой из этих трех функций. texreg Объект является просто контейнером для коэффициентов и т. д. и формально определяется с использованием класса S4. Чтобы создать texreg объект, вы можете использовать функцию конструктора createTexreg (как задокументировано на страницах справки), которая принимает все различные части информации в качестве аргументов, такие как стандартные ошибки и т. д. Или (лучше) вы можете использовать extract функция для извлечения этих частей информации из некоторой оценочной модели и возврата texreg объект для использования с любой из трех функций. Обычно вы делаете это, просто передавая список нескольких моделей texreg или же screenreg и т. д., и эта функция будет вызывать внутренне 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 объект.

Нахождение правильной информации в 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) показывает, что есть слот под названием model в объекте S4. Мы можем посмотреть на его содержание, позвонив 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, такие как names или же coef, Хотя это технически должно работать, потому что код выполняется внутри функции позже, это может легко привести к путанице при испытании, поэтому вам лучше этого избежать.

Далее нам нужно найти статистику соответствия. Изучая результаты 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(model)), БИК (BIC(model)), отклонение (deviance(model)) или журнал вероятности (logLik(model)[[1]]). Так что это то, что вы можете попробовать в первую очередь; но h2o пакет, кажется, не предлагает такие удобные методы.

Добавление информации в extract.H2OBinomialModel функция

Теперь, когда мы нашли всю необходимую нам информацию, мы можем добавить их в extract.H2OBinomialModel Функция, которую мы определили выше.

Тем не менее, мы хотели бы позволить пользователю решать, предпочитает ли он или она необработанные или стандартизированные коэффициенты, и мы хотим, чтобы пользователь решал, какую статистику о соответствии качества следует сообщать, поэтому мы добавляем различные логические аргументы в заголовок функции. а затем использовать if-условия внутри функции, чтобы проверить, следует ли встраивать соответствующую статистику в 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 метод для texreg версия 1.36.13, которая доступна на 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: р-значения
  • ci.low: нижняя граница доверительного интервала
  • ci.up: верхняя граница доверительного интервала
  • model.name: название текущей модели

Обратите внимание, что должны использоваться либо доверительные интервалы, либо стандартные ошибки и значения p, а не оба.

Манипулирование texreg объекты

Помимо передачи моделей в screenreg, texreg, или же htmlreg функции, можно сохранить извлеченную информацию в 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:

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 объект вместо исходной модели при вызове, например, 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 вызов. Я включил H2OBinomialModel метод в последнем texreg версия 1.36.13, а также исправление ошибок при использовании моделей без стандартных ошибок (например, этой).

Вы можете использовать пакет R xtable с H2OTable h2o (или knitr, если вы преобразуете H2OTable в H2OFrame, используя as.h2o(your_H2OTable)), если вы извлекаете их из выходных данных модели.

например, чтобы создать красивую таблицу из коэффициентов модели, вам необходимо сначала извлечь таблицу коэффициентов с помощью model.output.1@model$coefficients_tableтогда вы можете использовать xtable: xtable(prostate.glm@model$coefficients_table) распечатать латексный код.

для просмотра рядом есть несколько сообщений о том, как это сделать в knitr или xtable, или в xtable и sweave

Нет, нет пакета, который делает это в настоящее время. Пакет с метлой пока не поддерживает модели H2O - это было бы круто! Может быть, это может произойти в будущем. Если есть способ "привести в порядок" вывод модели в R data.frame, используя метлу или аналогичную функциональность, тогда xtable и т. Д. Будут работать хорошо.

Другие вопросы по тегам