XGBoost自定义损失函数无法复制Binary:Logistic目标

时间:2019-10-09 10:40:39

标签: r xgboost objective-function

我正在RStudio中工作,并希望为XGBoost开发自定义目标函数。为了确保我了解该过程的工作原理,我试图编写一个目标函数来复制“ binary:logistic”目标。但是,我的自定义目标函数产生的结果却大不相同(通常差很多)。

基于the examples on the XGBoost github repo,我的自定义目标函数如下所示:

# custom objective function
logloss <- function(preds, dtrain){

  # Get weights and labels
  labels<- getinfo(dtrain, "label")

  # Apply logistic transform to predictions
  preds <- 1/(1 + exp(-preds))

  # Find gradient and hessian
  grad <- (preds - labels)
  hess <- preds * (1-preds)

  return(list("grad" = grad, "hess" = hess))
}

基于this medium blog post,这似乎与XGBoost二进制目标中实现的内容相匹配。

使用一些简单的测试数据,我对内置目标的最终训练均方根值为〜0.468,而使用我的自定义目标则为〜0.72。

下面的代码可用于生成测试数据并重现问题。

有人可以解释为什么我的代码没有重现客观的“ binary:logistic”行为吗?我正在使用XGBoost R-Package v0.90.0.2。

library(data.table)
library(xgboost)

# Generate test data
generate_test_data <- function(n_rows = 1e5, feature_count = 5, train_fraction = 0.5){

  # Make targets
  test_data <- data.table(
    target = sign(runif(n = n_rows, min=-1, max=1))
  )

  # Add feature columns.These are normally distributed and shifted by the target
  # in order to create a noisy signal
  for(feature in 1:feature_count){

    # Randomly create features of the noise
    mu <- runif(1, min=-1, max=1)
    sdev <- runif(1, min=5, max=10)

    # Create noisy signal
    test_data[, paste0("feature_", feature) := rnorm(
      n=n_rows, mean = mu, sd = sdev)*target + target]
  }

  # Split data into test/train
  test_data[, index_fraction := .I/.N]
  split_data <- list(
    "train" = test_data[index_fraction < (train_fraction)],
    "test" = test_data[index_fraction >= (train_fraction)]
  )

  # Make vector of feature names
  feature_names <- paste0("feature_", 1:feature_count)

  # Make test/train matrix and labels
  split_data[["test_trix"]] <- as.matrix(split_data$test[, feature_names, with=FALSE])
  split_data[["train_trix"]] <- as.matrix(split_data$train[, feature_names, with=FALSE])
  split_data[["test_labels"]] <- as.logical(split_data$test$target + 1)    
  split_data[["train_labels"]] <- as.logical(split_data$train$target + 1)

  return(split_data)
}

# Build the tree
build_model <- function(split_data, objective){

  # Make evaluation matrix
  train_dtrix <-
    xgb.DMatrix(
      data = split_data$train_trix, label = split_data$train_labels)

  # Train the model
  model <- xgb.train(
    data = train_dtrix,
    watchlist = list(
      train = train_dtrix),
    nrounds = 5,
    objective =  objective,
    eval_metric = "rmse"
  )

  return(model)
}

split_data <- generate_test_data()
cat("\nUsing built-in binary:logistic objective.\n")
test_1 <- build_model(split_data, "binary:logistic")
cat("\n\nUsing custom objective")
test_2 <- build_model(split_data, logloss)

0 个答案:

没有答案