Xgboost для выживания с использованием мл в R - PullRequest
4 голосов
/ 24 июня 2019

Я хотел бы использовать mlr для запуска xgboost на данных о выживаемости, прошедших правую цензуру в R. Код xgboost перечисляет целевую функцию выживания: cox, которая говорит:

выживание: cox: регрессия Кокса дляДанные о времени выживания, прошедшие цензуру справа (отрицательные значения считаются цензурой справа).

Mlr 2, который я использую, поддерживает xgboost только для учащихся, изучающих регрессию и классификацию.Если я пытаюсь использовать встроенный регрессивный ученик для xgboost, он использует mse в качестве метрики оценки.Поэтому я попытался изменить метрику на cindex и получил ошибку

Показатели: cindex cindex
Ошибка в FUN (X [[i]], ...): показатель cindex не поддерживает задачунаберите regr!

Итак, я попытался написать нового ученика по выживанию для xgboost, который является просто копией ученика регрессии, но с «Regr» изменен на «Surv», но, конечно, он ожидаетцель имеет 2 столбца - время и статус - и не принимает отрицательные времена, тогда как xgboost ожидает только один столбец - время - и предполагает, что любые строки с отрицательным значением для времени подвергаются цензуре.

Ниже приведеночто я пробовалЕсть ли способ достичь этого в mlr2 или mlr3?

  1. Использование встроенного регрессионного ученика для xgboost:
    data(veteran)
    veteran_xgb <- veteran
    veteran_xgb <- veteran_xgb[c("trt", "karno", "diagtime", "age", "prior", "time")]
    veteran_xgb$time <- ifelse(veteran$status==1, veteran$time, -veteran$time)

    xgb.task <- makeRegrTask(id="XGBOOST_VET", data = veteran_xgb, target="time")
    xgb_learner <- makeLearner(id="xgboost",
                              cl="regr.xgboost",
                              predict.type = "response",
                              par.vals = list(
                                  objective = "survival:cox",
                                  eval_metric = "cox-nloglik",
                                  nrounds = 200
                                )
                              )

    learners = list(xgb_learner)
    outer = makeResampleDesc("CV", iters=5) # Benchmarking
    bmr = benchmark(learners, xgb.task, outer, show.info = TRUE)
Использование настраиваемого ученика-выжившего для xgboost:
    data(veteran)
    veteran_xgb <- veteran
    veteran_xgb <- veteran_xgb[c("trt", "karno", "diagtime", "age", "prior", "time", "status")]
    veteran_xgb$time <- ifelse(veteran$status==1, veteran$time, -veteran$time)

    xgb.task <- makeSurvTask(id="XGBOOST_VET", data = veteran_xgb, target = c("time", "status"))
    xgb_learner <- makeLearner(id="xgboost",
                              cl="surv.xgboost",
                              predict.type = "response",
                              par.vals = list(
                                  objective = "survival:cox",
                                  eval_metric = "cox-nloglik",
                                  nrounds = 200
                                )
                              )

    learners = list(xgb_learner)
    outer = makeResampleDesc("CV", iters=5) # Benchmarking
    surv.measures = list(cindex)
    bmr = benchmark(learners, xgb.task, outer, surv.measures, show.info = TRUE)

Файл RLearner_surv_xgboost.R можно загрузить с OneDrive здесь https://1drv.ms/u/s!AjTjdzp0sDJRrhZtZF5-HZF2BrBB?e=FNLS94

1 Ответ

3 голосов
/ 26 июня 2019

Я нашел решение и обновил своего ученика здесь: https://1drv.ms/u/s!AjTjdzp0sDJRrhewy0yx3Wot3FiI?e=sxRrTN

Хитрость заключалась в том, чтобы изменить функцию trainlearner.surv.xgboost.Будучи учеником по выживанию, он ожидает передачи данных с целью, содержащей 2 столбца времени и статуса.Но внутри этого учащегося мы можем вычислить цель, которую ожидает xgboost, с отрицательным временем для цензурированных данных, а затем передать эту новую цель, состоящую из одного столбца, в xgboost:

 trainLearner.surv.xgboost = function(.learner, .task, .subset, .weights = NULL,  ...) {
  parlist = list(...)

  if (is.null(parlist$objective))
  {
    parlist$objective = "survival:cox"
    parlist$eval_metric = "cox-nloglik"
  }

  task.data = getTaskData(.task, .subset, target.extra = TRUE)
  survtime <- ifelse(task.data$target$status==1, task.data$target$time, -task.data$target$time)

  parlist$data = xgboost::xgb.DMatrix(data = data.matrix(task.data$data), label = survtime)

  if (!is.null(.weights))
    xgboost::setinfo(parlist$data, "weight", .weights)

  if (is.null(parlist$watchlist))
    parlist$watchlist = list(train = parlist$data)

  do.call(xgboost::xgb.train, parlist)
}

Затем, чтобы использовать этого нового ученика:

library(xgboost)
library(survival)
library(mlr)
source("RLearner_surv_xgboost.R")

data(veteran)
veteran.xgb <- veteran[, !(names(veteran) %in% c("celltype"))]

xgb.task <- makeSurvTask(id="XGBOOST_VET", data = veteran.xgb, target = c("time", "status"))
surv.measures = list(cindex)
outer= makeResampleDesc("CV", iters=5)

xgb.learner <- makeLearner(id="xgboost",
                          cl="surv.xgboost",
                          predict.type = "response")
learners = list(xgb.learner)
bmr = benchmark(learners, xgb.task, outer, surv.measures, show.info = TRUE)
...