From fa2215eec48f371bd192c1d04bb05a302fe990dc Mon Sep 17 00:00:00 2001 From: David Cortes Date: Thu, 14 Oct 2021 23:35:17 -0300 Subject: [PATCH 01/17] add print and summary S3 method --- R-package/NAMESPACE | 2 ++ R-package/R/lgb.Booster.R | 47 ++++++++++++++++++++++++++++ R-package/man/print.lgb.Booster.Rd | 17 ++++++++++ R-package/man/summary.lgb.Booster.Rd | 19 +++++++++++ R-package/src/lightgbm_R.cpp | 10 ++++++ R-package/src/lightgbm_R.h | 9 ++++++ include/LightGBM/c_api.h | 9 ++++++ src/c_api.cpp | 7 +++++ 8 files changed, 120 insertions(+) create mode 100644 R-package/man/print.lgb.Booster.Rd create mode 100644 R-package/man/summary.lgb.Booster.Rd diff --git a/R-package/NAMESPACE b/R-package/NAMESPACE index 8df060d28605..99139fe99276 100644 --- a/R-package/NAMESPACE +++ b/R-package/NAMESPACE @@ -6,9 +6,11 @@ S3method(dimnames,lgb.Dataset) S3method(get_field,lgb.Dataset) S3method(getinfo,lgb.Dataset) S3method(predict,lgb.Booster) +S3method(print,lgb.Booster) S3method(set_field,lgb.Dataset) S3method(setinfo,lgb.Dataset) S3method(slice,lgb.Dataset) +S3method(summary,lgb.Booster) export(get_field) export(getinfo) export(lgb.Dataset) diff --git a/R-package/R/lgb.Booster.R b/R-package/R/lgb.Booster.R index 586f3a38899d..995fee6e1103 100644 --- a/R-package/R/lgb.Booster.R +++ b/R-package/R/lgb.Booster.R @@ -810,6 +810,53 @@ predict.lgb.Booster <- function(object, ) } +#' @name print.lgb.Booster +#' @title Print method for LightGBM model +#' @description Show summary information about a LightGBM model object (same as \code{summary}). +#' @param x Object of class \code{lgb.Booster} +#' @return The same input `x`, returned as invisible. +#' @export +print.lgb.Booster <- function(x) { + handle <- x$.__enclos_env__$private$handle + handle_is_null <- lgb.is.null.handle(handle) + + if (!handle_is_null) { + cat(sprintf("LightGBM Model (%d trees)\n", x$current_iter())) + } else { + cat("LightGBM Model\n") + } + + if (!handle_is_null) { + if (x$.__enclos_env__$private$num_class == 1L) { + cat(sprintf("Objective: %s\n", x$params$objective)) + } else { + cat(sprintf("Objective: %s (%d classes)\n" + , x$params$objective + , x$.__enclos_env__$private$num_class == 1L)) + } + } else { + cat("(Booster handle is invalid)\n") + } + + if (!handle_is_null) { + ncols <- .Call(LGBM_BoosterGetNumFeatures_R, handle) + cat(sprintf("Fitted to dataset with %d columns\n", ncols)) + } + + return(invisible(x)) +} + +#' @name summary.lgb.Booster +#' @title Summary method for LightGBM model +#' @description Show summary information about a LightGBM model object (same as \code{print}). +#' @param object Object of class \code{lgb.Booster} +#' @param ... Not used +#' @return The same input `object`, returned as invisible. +#' @export +summary.lgb.Booster <- function(object, ...) { + print(object) +} + #' @name lgb.load #' @title Load LightGBM model #' @description Load LightGBM takes in either a file path or model string. diff --git a/R-package/man/print.lgb.Booster.Rd b/R-package/man/print.lgb.Booster.Rd new file mode 100644 index 000000000000..2e0c3f97ba95 --- /dev/null +++ b/R-package/man/print.lgb.Booster.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lgb.Booster.R +\name{print.lgb.Booster} +\alias{print.lgb.Booster} +\title{Print method for LightGBM model} +\usage{ +\method{print}{lgb.Booster}(x) +} +\arguments{ +\item{x}{Object of class \code{lgb.Booster}} +} +\value{ +The same input `x`, returned as invisible. +} +\description{ +Show summary information about a LightGBM model object (same as \code{summary}). +} diff --git a/R-package/man/summary.lgb.Booster.Rd b/R-package/man/summary.lgb.Booster.Rd new file mode 100644 index 000000000000..8af5158feb15 --- /dev/null +++ b/R-package/man/summary.lgb.Booster.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lgb.Booster.R +\name{summary.lgb.Booster} +\alias{summary.lgb.Booster} +\title{Summary method for LightGBM model} +\usage{ +\method{summary}{lgb.Booster}(object, ...) +} +\arguments{ +\item{object}{Object of class \code{lgb.Booster}} + +\item{...}{Not used} +} +\value{ +The same input `object`, returned as invisible. +} +\description{ +Show summary information about a LightGBM model object (same as \code{print}). +} diff --git a/R-package/src/lightgbm_R.cpp b/R-package/src/lightgbm_R.cpp index 99dd666dbf9e..43eb40db5a38 100644 --- a/R-package/src/lightgbm_R.cpp +++ b/R-package/src/lightgbm_R.cpp @@ -525,6 +525,15 @@ SEXP LGBM_BoosterGetNumClasses_R(SEXP handle, R_API_END(); } +SEXP LGBM_BoosterGetNumFeatures_R(SEXP handle) { + R_API_BEGIN(); + _AssertBoosterHandleNotNull(handle); + int out = 0; + CHECK_CALL(LGBM_BoosterGetNumFeatures(R_ExternalPtrAddr(handle), &out)); + return Rf_ScalarInteger(out); + R_API_END(); +} + SEXP LGBM_BoosterUpdateOneIter_R(SEXP handle) { R_API_BEGIN(); _AssertBoosterHandleNotNull(handle); @@ -889,6 +898,7 @@ static const R_CallMethodDef CallEntries[] = { {"LGBM_BoosterResetTrainingData_R" , (DL_FUNC) &LGBM_BoosterResetTrainingData_R , 2}, {"LGBM_BoosterResetParameter_R" , (DL_FUNC) &LGBM_BoosterResetParameter_R , 2}, {"LGBM_BoosterGetNumClasses_R" , (DL_FUNC) &LGBM_BoosterGetNumClasses_R , 2}, + {"LGBM_BoosterGetNumFeatures_R" , (DL_FUNC) &LGBM_BoosterGetNumFeatures_R , 1}, {"LGBM_BoosterUpdateOneIter_R" , (DL_FUNC) &LGBM_BoosterUpdateOneIter_R , 1}, {"LGBM_BoosterUpdateOneIterCustom_R", (DL_FUNC) &LGBM_BoosterUpdateOneIterCustom_R, 4}, {"LGBM_BoosterRollbackOneIter_R" , (DL_FUNC) &LGBM_BoosterRollbackOneIter_R , 1}, diff --git a/R-package/src/lightgbm_R.h b/R-package/src/lightgbm_R.h index 16a87c3a611f..070e107a8a4f 100644 --- a/R-package/src/lightgbm_R.h +++ b/R-package/src/lightgbm_R.h @@ -302,6 +302,15 @@ LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumClasses_R( SEXP out ); +/*! +* \brief Get number of features +* \param handle Booster handle +* \return R integer +*/ +LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumFeatures_R( + SEXP handle +); + /*! * \brief update the model in one round * \param handle Booster handle diff --git a/include/LightGBM/c_api.h b/include/LightGBM/c_api.h index b5542891b063..bdeb245ae1be 100644 --- a/include/LightGBM/c_api.h +++ b/include/LightGBM/c_api.h @@ -1263,6 +1263,15 @@ LIGHTGBM_C_EXPORT int LGBM_BoosterSetLeafValue(BoosterHandle handle, int leaf_idx, double val); +/*! + * \brief Get number of features (columns) to which a booster was fit. + * \param handle Handle of booster + * \param[out] out_val Output result from the specified leaf + * \return 0 when succeed, -1 when failure happens + */ +LIGHTGBM_C_EXPORT int LGBM_BoosterGetNumFeatures(BoosterHandle handle, + int *out_val); + /*! * \brief Get model feature importance. * \param handle Handle of booster diff --git a/src/c_api.cpp b/src/c_api.cpp index bc3bfc3b2434..be5ccc400e43 100644 --- a/src/c_api.cpp +++ b/src/c_api.cpp @@ -2308,6 +2308,13 @@ int LGBM_BoosterSetLeafValue(BoosterHandle handle, API_END(); } +int LGBM_BoosterGetNumFeatures(BoosterHandle handle, int *out_val) { + API_BEGIN(); + Booster* ref_booster = reinterpret_cast(handle); + *out_val = ref_booster->GetBoosting()->MaxFeatureIdx() + 1; + API_END(); +} + int LGBM_BoosterFeatureImportance(BoosterHandle handle, int num_iteration, int importance_type, From fa9e8e92ed6ccc6d0686fe8b17c036d178ad264b Mon Sep 17 00:00:00 2001 From: David Cortes Date: Thu, 14 Oct 2021 23:53:12 -0300 Subject: [PATCH 02/17] correct wrong signature --- R-package/R/lgb.Booster.R | 3 ++- R-package/man/print.lgb.Booster.Rd | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/R-package/R/lgb.Booster.R b/R-package/R/lgb.Booster.R index 995fee6e1103..3accedd404d8 100644 --- a/R-package/R/lgb.Booster.R +++ b/R-package/R/lgb.Booster.R @@ -814,9 +814,10 @@ predict.lgb.Booster <- function(object, #' @title Print method for LightGBM model #' @description Show summary information about a LightGBM model object (same as \code{summary}). #' @param x Object of class \code{lgb.Booster} +#' @param ... Not used #' @return The same input `x`, returned as invisible. #' @export -print.lgb.Booster <- function(x) { +print.lgb.Booster <- function(x, ...) { handle <- x$.__enclos_env__$private$handle handle_is_null <- lgb.is.null.handle(handle) diff --git a/R-package/man/print.lgb.Booster.Rd b/R-package/man/print.lgb.Booster.Rd index 2e0c3f97ba95..47ae13189891 100644 --- a/R-package/man/print.lgb.Booster.Rd +++ b/R-package/man/print.lgb.Booster.Rd @@ -4,10 +4,12 @@ \alias{print.lgb.Booster} \title{Print method for LightGBM model} \usage{ -\method{print}{lgb.Booster}(x) +\method{print}{lgb.Booster}(x, ...) } \arguments{ \item{x}{Object of class \code{lgb.Booster}} + +\item{...}{Not used} } \value{ The same input `x`, returned as invisible. From 1c5dd263464abacd0fc9e002bd423db3ca3606cd Mon Sep 17 00:00:00 2001 From: David Cortes Date: Fri, 15 Oct 2021 00:12:37 -0300 Subject: [PATCH 03/17] attempt at bypassing linter --- R-package/R/lgb.Booster.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R-package/R/lgb.Booster.R b/R-package/R/lgb.Booster.R index 3accedd404d8..29bcd4b4050e 100644 --- a/R-package/R/lgb.Booster.R +++ b/R-package/R/lgb.Booster.R @@ -818,6 +818,7 @@ predict.lgb.Booster <- function(object, #' @return The same input `x`, returned as invisible. #' @export print.lgb.Booster <- function(x, ...) { + # nolint start handle <- x$.__enclos_env__$private$handle handle_is_null <- lgb.is.null.handle(handle) @@ -843,6 +844,7 @@ print.lgb.Booster <- function(x, ...) { ncols <- .Call(LGBM_BoosterGetNumFeatures_R, handle) cat(sprintf("Fitted to dataset with %d columns\n", ncols)) } + # nolint end return(invisible(x)) } From 38d5db6b92693109c458602bf77b00f32e4c8c68 Mon Sep 17 00:00:00 2001 From: david-cortes Date: Fri, 15 Oct 2021 06:43:55 +0300 Subject: [PATCH 04/17] Update R-package/R/lgb.Booster.R Co-authored-by: James Lamb --- R-package/R/lgb.Booster.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R-package/R/lgb.Booster.R b/R-package/R/lgb.Booster.R index 29bcd4b4050e..2d72a0bdd84a 100644 --- a/R-package/R/lgb.Booster.R +++ b/R-package/R/lgb.Booster.R @@ -834,7 +834,7 @@ print.lgb.Booster <- function(x, ...) { } else { cat(sprintf("Objective: %s (%d classes)\n" , x$params$objective - , x$.__enclos_env__$private$num_class == 1L)) + , x$.__enclos_env__$private$num_class)) } } else { cat("(Booster handle is invalid)\n") From 4746829ff3b2004b9b28833d81f573011b93f257 Mon Sep 17 00:00:00 2001 From: david-cortes Date: Fri, 15 Oct 2021 06:44:07 +0300 Subject: [PATCH 05/17] Update R-package/src/lightgbm_R.h Co-authored-by: James Lamb --- R-package/src/lightgbm_R.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R-package/src/lightgbm_R.h b/R-package/src/lightgbm_R.h index 070e107a8a4f..9883b0477d19 100644 --- a/R-package/src/lightgbm_R.h +++ b/R-package/src/lightgbm_R.h @@ -303,7 +303,7 @@ LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumClasses_R( ); /*! -* \brief Get number of features +* \brief Get number of features in the training data used when fitting this Booster. * \param handle Booster handle * \return R integer */ From 2f96422332a55d745ec0b242065b858fed19e4ef Mon Sep 17 00:00:00 2001 From: david-cortes Date: Fri, 15 Oct 2021 06:44:32 +0300 Subject: [PATCH 06/17] Update include/LightGBM/c_api.h Co-authored-by: James Lamb --- include/LightGBM/c_api.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/LightGBM/c_api.h b/include/LightGBM/c_api.h index bdeb245ae1be..6c76278439f5 100644 --- a/include/LightGBM/c_api.h +++ b/include/LightGBM/c_api.h @@ -1264,9 +1264,9 @@ LIGHTGBM_C_EXPORT int LGBM_BoosterSetLeafValue(BoosterHandle handle, double val); /*! - * \brief Get number of features (columns) to which a booster was fit. + * \brief Get number of features in the training data used when fitting this Booster. * \param handle Handle of booster - * \param[out] out_val Output result from the specified leaf + * \param[out] out_val Number of features in the training data used when fitting this Booster. * \return 0 when succeed, -1 when failure happens */ LIGHTGBM_C_EXPORT int LGBM_BoosterGetNumFeatures(BoosterHandle handle, From 8b40215ee924ca8ef828ea2a38a3cd1e11c7e788 Mon Sep 17 00:00:00 2001 From: David Cortes Date: Fri, 15 Oct 2021 13:35:08 -0300 Subject: [PATCH 07/17] add more tests --- R-package/tests/testthat/test_lgb.Booster.R | 62 +++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/R-package/tests/testthat/test_lgb.Booster.R b/R-package/tests/testthat/test_lgb.Booster.R index b76acd9d9d09..cd6d9a66e202 100644 --- a/R-package/tests/testthat/test_lgb.Booster.R +++ b/R-package/tests/testthat/test_lgb.Booster.R @@ -1035,3 +1035,65 @@ test_that("boosters with linear models at leaves can be written to RDS and re-lo preds2 <- predict(bst2, X) expect_identical(preds, preds2) }) + +test_that("Booster's print, show, and summary work correctly", { + check_methods_work <- function(model) { + expect_error(print(model), NA) + expect_error(show(model), NA) + expect_error(summary(model), NA) + model$finalize() + expect_error(print(model), NA) + expect_error(show(model), NA) + expect_error(summary(model), NA) + } + + data("mtcars") + model <- lgb.train( + params = list(objective = "regression") + , data = lgb.Dataset( + as.matrix(mtcars[, -1]) + , label = mtcars$mpg) + , verbose = 0 + , nrounds = 5L + ) + check_methods_work(model) + + data("iris") + model <- lgb.train( + params = list(objective = "multiclass", num_class = 3L) + , data = lgb.Dataset( + as.matrix(iris[, -5]) + , label = as.numeric(factor(iris$Species)) - 1 + ) + , verbose = 0 + , nrounds = 5L + ) + check_methods_work(model) +}) + +test_that("LGBM_BoosterGetNumFeatures_R returns correct outputs", { + data("mtcars") + model <- lgb.train( + params = list(objective = "regression") + , data = lgb.Dataset( + as.matrix(mtcars[, -1]) + , label = mtcars$mpg) + , verbose = 0 + , nrounds = 5L + ) + ncols <- .Call(LGBM_BoosterGetNumFeatures_R, model$.__enclos_env__$private$handle) + expect_equal(ncols, ncol(mtcars) - 1L) + + data("iris") + model <- lgb.train( + params = list(objective = "multiclass", num_class = 3L) + , data = lgb.Dataset( + as.matrix(iris[, -5]) + , label = as.numeric(factor(iris$Species)) - 1 + ) + , verbose = 0 + , nrounds = 5L + ) + ncols <- .Call(LGBM_BoosterGetNumFeatures_R, model$.__enclos_env__$private$handle) + expect_equal(ncols, ncol(iris) - 1L) +}) From 560cbeb80a4b0e3a7a2dee90e70bcba1ef0f17a1 Mon Sep 17 00:00:00 2001 From: David Cortes Date: Fri, 15 Oct 2021 13:46:23 -0300 Subject: [PATCH 08/17] linter --- R-package/tests/testthat/test_lgb.Booster.R | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/R-package/tests/testthat/test_lgb.Booster.R b/R-package/tests/testthat/test_lgb.Booster.R index cd6d9a66e202..1d368be57af4 100644 --- a/R-package/tests/testthat/test_lgb.Booster.R +++ b/R-package/tests/testthat/test_lgb.Booster.R @@ -1051,9 +1051,9 @@ test_that("Booster's print, show, and summary work correctly", { model <- lgb.train( params = list(objective = "regression") , data = lgb.Dataset( - as.matrix(mtcars[, -1]) + as.matrix(mtcars[, -1L]) , label = mtcars$mpg) - , verbose = 0 + , verbose = 0L , nrounds = 5L ) check_methods_work(model) @@ -1062,10 +1062,10 @@ test_that("Booster's print, show, and summary work correctly", { model <- lgb.train( params = list(objective = "multiclass", num_class = 3L) , data = lgb.Dataset( - as.matrix(iris[, -5]) - , label = as.numeric(factor(iris$Species)) - 1 + as.matrix(iris[, -5L]) + , label = as.numeric(factor(iris$Species)) - 1.0 ) - , verbose = 0 + , verbose = 0L , nrounds = 5L ) check_methods_work(model) @@ -1076,9 +1076,9 @@ test_that("LGBM_BoosterGetNumFeatures_R returns correct outputs", { model <- lgb.train( params = list(objective = "regression") , data = lgb.Dataset( - as.matrix(mtcars[, -1]) + as.matrix(mtcars[, -1L]) , label = mtcars$mpg) - , verbose = 0 + , verbose = 0L , nrounds = 5L ) ncols <- .Call(LGBM_BoosterGetNumFeatures_R, model$.__enclos_env__$private$handle) @@ -1088,10 +1088,10 @@ test_that("LGBM_BoosterGetNumFeatures_R returns correct outputs", { model <- lgb.train( params = list(objective = "multiclass", num_class = 3L) , data = lgb.Dataset( - as.matrix(iris[, -5]) - , label = as.numeric(factor(iris$Species)) - 1 + as.matrix(iris[, -5L]) + , label = as.numeric(factor(iris$Species)) - 1.0 ) - , verbose = 0 + , verbose = 0L , nrounds = 5L ) ncols <- .Call(LGBM_BoosterGetNumFeatures_R, model$.__enclos_env__$private$handle) From b3e14e60329ca96d1a02433b42282c7d0da363fa Mon Sep 17 00:00:00 2001 From: David Cortes Date: Fri, 15 Oct 2021 13:59:50 -0300 Subject: [PATCH 09/17] don't pluralize single tree --- R-package/R/lgb.Booster.R | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/R-package/R/lgb.Booster.R b/R-package/R/lgb.Booster.R index 2d72a0bdd84a..fbfb6e342ab4 100644 --- a/R-package/R/lgb.Booster.R +++ b/R-package/R/lgb.Booster.R @@ -823,7 +823,12 @@ print.lgb.Booster <- function(x, ...) { handle_is_null <- lgb.is.null.handle(handle) if (!handle_is_null) { - cat(sprintf("LightGBM Model (%d trees)\n", x$current_iter())) + ntrees <- x$current_iter() + if (ntrees == 1L) { + cat("LightGBM Model (1 tree)\n") + } else { + cat(sprintf("LightGBM Model (%d trees)\n", ntrees)) + } } else { cat("LightGBM Model\n") } From b1b2ab90afefe72ff85581156237734041388764 Mon Sep 17 00:00:00 2001 From: David Cortes Date: Sat, 16 Oct 2021 13:54:11 -0300 Subject: [PATCH 10/17] remove duplicated function --- R-package/R/lgb.Booster.R | 2 +- R-package/src/lightgbm_R.cpp | 6 +++--- include/LightGBM/c_api.h | 9 --------- src/c_api.cpp | 7 ------- 4 files changed, 4 insertions(+), 20 deletions(-) diff --git a/R-package/R/lgb.Booster.R b/R-package/R/lgb.Booster.R index fbfb6e342ab4..912769360d36 100644 --- a/R-package/R/lgb.Booster.R +++ b/R-package/R/lgb.Booster.R @@ -846,7 +846,7 @@ print.lgb.Booster <- function(x, ...) { } if (!handle_is_null) { - ncols <- .Call(LGBM_BoosterGetNumFeatures_R, handle) + ncols <- .Call(LGBM_BoosterGetNumFeature_R, handle) cat(sprintf("Fitted to dataset with %d columns\n", ncols)) } # nolint end diff --git a/R-package/src/lightgbm_R.cpp b/R-package/src/lightgbm_R.cpp index 43eb40db5a38..2150e652841f 100644 --- a/R-package/src/lightgbm_R.cpp +++ b/R-package/src/lightgbm_R.cpp @@ -525,11 +525,11 @@ SEXP LGBM_BoosterGetNumClasses_R(SEXP handle, R_API_END(); } -SEXP LGBM_BoosterGetNumFeatures_R(SEXP handle) { +SEXP LGBM_BoosterGetNumFeature_R(SEXP handle) { R_API_BEGIN(); _AssertBoosterHandleNotNull(handle); int out = 0; - CHECK_CALL(LGBM_BoosterGetNumFeatures(R_ExternalPtrAddr(handle), &out)); + CHECK_CALL(LGBM_BoosterGetNumFeature(R_ExternalPtrAddr(handle), &out)); return Rf_ScalarInteger(out); R_API_END(); } @@ -898,7 +898,7 @@ static const R_CallMethodDef CallEntries[] = { {"LGBM_BoosterResetTrainingData_R" , (DL_FUNC) &LGBM_BoosterResetTrainingData_R , 2}, {"LGBM_BoosterResetParameter_R" , (DL_FUNC) &LGBM_BoosterResetParameter_R , 2}, {"LGBM_BoosterGetNumClasses_R" , (DL_FUNC) &LGBM_BoosterGetNumClasses_R , 2}, - {"LGBM_BoosterGetNumFeatures_R" , (DL_FUNC) &LGBM_BoosterGetNumFeatures_R , 1}, + {"LGBM_BoosterGetNumFeature_R" , (DL_FUNC) &LGBM_BoosterGetNumFeature_R , 1}, {"LGBM_BoosterUpdateOneIter_R" , (DL_FUNC) &LGBM_BoosterUpdateOneIter_R , 1}, {"LGBM_BoosterUpdateOneIterCustom_R", (DL_FUNC) &LGBM_BoosterUpdateOneIterCustom_R, 4}, {"LGBM_BoosterRollbackOneIter_R" , (DL_FUNC) &LGBM_BoosterRollbackOneIter_R , 1}, diff --git a/include/LightGBM/c_api.h b/include/LightGBM/c_api.h index 6c76278439f5..b5542891b063 100644 --- a/include/LightGBM/c_api.h +++ b/include/LightGBM/c_api.h @@ -1263,15 +1263,6 @@ LIGHTGBM_C_EXPORT int LGBM_BoosterSetLeafValue(BoosterHandle handle, int leaf_idx, double val); -/*! - * \brief Get number of features in the training data used when fitting this Booster. - * \param handle Handle of booster - * \param[out] out_val Number of features in the training data used when fitting this Booster. - * \return 0 when succeed, -1 when failure happens - */ -LIGHTGBM_C_EXPORT int LGBM_BoosterGetNumFeatures(BoosterHandle handle, - int *out_val); - /*! * \brief Get model feature importance. * \param handle Handle of booster diff --git a/src/c_api.cpp b/src/c_api.cpp index be5ccc400e43..bc3bfc3b2434 100644 --- a/src/c_api.cpp +++ b/src/c_api.cpp @@ -2308,13 +2308,6 @@ int LGBM_BoosterSetLeafValue(BoosterHandle handle, API_END(); } -int LGBM_BoosterGetNumFeatures(BoosterHandle handle, int *out_val) { - API_BEGIN(); - Booster* ref_booster = reinterpret_cast(handle); - *out_val = ref_booster->GetBoosting()->MaxFeatureIdx() + 1; - API_END(); -} - int LGBM_BoosterFeatureImportance(BoosterHandle handle, int num_iteration, int importance_type, From e7d37c0082c6cec21cb8c81854eba011ebb57d12 Mon Sep 17 00:00:00 2001 From: David Cortes Date: Sat, 16 Oct 2021 14:54:08 -0300 Subject: [PATCH 11/17] update changed function name --- R-package/src/lightgbm_R.h | 9 --------- R-package/tests/testthat/test_lgb.Booster.R | 6 +++--- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/R-package/src/lightgbm_R.h b/R-package/src/lightgbm_R.h index 9883b0477d19..16a87c3a611f 100644 --- a/R-package/src/lightgbm_R.h +++ b/R-package/src/lightgbm_R.h @@ -302,15 +302,6 @@ LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumClasses_R( SEXP out ); -/*! -* \brief Get number of features in the training data used when fitting this Booster. -* \param handle Booster handle -* \return R integer -*/ -LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumFeatures_R( - SEXP handle -); - /*! * \brief update the model in one round * \param handle Booster handle diff --git a/R-package/tests/testthat/test_lgb.Booster.R b/R-package/tests/testthat/test_lgb.Booster.R index 1d368be57af4..a4eef52418bd 100644 --- a/R-package/tests/testthat/test_lgb.Booster.R +++ b/R-package/tests/testthat/test_lgb.Booster.R @@ -1071,7 +1071,7 @@ test_that("Booster's print, show, and summary work correctly", { check_methods_work(model) }) -test_that("LGBM_BoosterGetNumFeatures_R returns correct outputs", { +test_that("LGBM_BoosterGetNumFeature_R returns correct outputs", { data("mtcars") model <- lgb.train( params = list(objective = "regression") @@ -1081,7 +1081,7 @@ test_that("LGBM_BoosterGetNumFeatures_R returns correct outputs", { , verbose = 0L , nrounds = 5L ) - ncols <- .Call(LGBM_BoosterGetNumFeatures_R, model$.__enclos_env__$private$handle) + ncols <- .Call(LGBM_BoosterGetNumFeature_R, model$.__enclos_env__$private$handle) expect_equal(ncols, ncol(mtcars) - 1L) data("iris") @@ -1094,6 +1094,6 @@ test_that("LGBM_BoosterGetNumFeatures_R returns correct outputs", { , verbose = 0L , nrounds = 5L ) - ncols <- .Call(LGBM_BoosterGetNumFeatures_R, model$.__enclos_env__$private$handle) + ncols <- .Call(LGBM_BoosterGetNumFeature_R, model$.__enclos_env__$private$handle) expect_equal(ncols, ncol(iris) - 1L) }) From 0e06c97e88172acd2e3f383e5db545c0c83de68b Mon Sep 17 00:00:00 2001 From: David Cortes Date: Sat, 16 Oct 2021 15:16:57 -0300 Subject: [PATCH 12/17] missing declaration --- R-package/src/lightgbm_R.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/R-package/src/lightgbm_R.h b/R-package/src/lightgbm_R.h index 16a87c3a611f..d9fe51b32f96 100644 --- a/R-package/src/lightgbm_R.h +++ b/R-package/src/lightgbm_R.h @@ -302,6 +302,16 @@ LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumClasses_R( SEXP out ); +/*! +* \brief Get number of features. +* \param handle Booster handle +* \param out Total number of features +* \return R NULL value +*/ +LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumFeature_R( + SEXP handle +); + /*! * \brief update the model in one round * \param handle Booster handle From b44f5d20f82f5943c40f24a03707e8939aa49b6a Mon Sep 17 00:00:00 2001 From: david-cortes Date: Sun, 17 Oct 2021 04:35:06 +0300 Subject: [PATCH 13/17] Update lightgbm_R.h --- R-package/src/lightgbm_R.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R-package/src/lightgbm_R.h b/R-package/src/lightgbm_R.h index d9fe51b32f96..41e2fbab13db 100644 --- a/R-package/src/lightgbm_R.h +++ b/R-package/src/lightgbm_R.h @@ -305,8 +305,7 @@ LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumClasses_R( /*! * \brief Get number of features. * \param handle Booster handle -* \param out Total number of features -* \return R NULL value +* \return Total number of features, as R integer */ LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumFeature_R( SEXP handle From 44f21bec58be03e099d92b3f987e48958d08d2fd Mon Sep 17 00:00:00 2001 From: david-cortes Date: Tue, 26 Oct 2021 18:41:29 +0300 Subject: [PATCH 14/17] Update R-package/tests/testthat/test_lgb.Booster.R Co-authored-by: James Lamb --- R-package/tests/testthat/test_lgb.Booster.R | 35 +++++++++++++++------ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/R-package/tests/testthat/test_lgb.Booster.R b/R-package/tests/testthat/test_lgb.Booster.R index a4eef52418bd..51cacfa81eab 100644 --- a/R-package/tests/testthat/test_lgb.Booster.R +++ b/R-package/tests/testthat/test_lgb.Booster.R @@ -1037,14 +1037,31 @@ test_that("boosters with linear models at leaves can be written to RDS and re-lo }) test_that("Booster's print, show, and summary work correctly", { - check_methods_work <- function(model) { - expect_error(print(model), NA) - expect_error(show(model), NA) - expect_error(summary(model), NA) + .have_same_handle <- function(model, other_model){ + expect_equal( + model$.__enclos_env__$private$handle + , other_model$.__enclos_env__$private$handle + ) + } + + .check_methods_work <- function(model) { + + # should work for fitted models + ret <- print(model) + .have_same_handle(ret, model) + ret <- show(model) + expect_null(ret) + ret <- summary(model) + .have_same_handle(ret, model) + + # should not fail for finalized models model$finalize() - expect_error(print(model), NA) - expect_error(show(model), NA) - expect_error(summary(model), NA) + ret <- print(model) + .have_same_handle(ret, model) + ret <- show(model) + expect_null(ret) + ret <- summary(model) + .have_same_handle(ret, model) } data("mtcars") @@ -1056,7 +1073,7 @@ test_that("Booster's print, show, and summary work correctly", { , verbose = 0L , nrounds = 5L ) - check_methods_work(model) + .check_methods_work(model) data("iris") model <- lgb.train( @@ -1068,7 +1085,7 @@ test_that("Booster's print, show, and summary work correctly", { , verbose = 0L , nrounds = 5L ) - check_methods_work(model) + .check_methods_work(model) }) test_that("LGBM_BoosterGetNumFeature_R returns correct outputs", { From a2a125b33f5ccbca10a52ac9cd4486277b55dfa7 Mon Sep 17 00:00:00 2001 From: David Cortes Date: Tue, 26 Oct 2021 12:50:29 -0300 Subject: [PATCH 15/17] accommodate custom objectives in print --- R-package/R/lgb.Booster.R | 8 +++-- R-package/tests/testthat/test_lgb.Booster.R | 34 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/R-package/R/lgb.Booster.R b/R-package/R/lgb.Booster.R index 912769360d36..f4f5aaa4313a 100644 --- a/R-package/R/lgb.Booster.R +++ b/R-package/R/lgb.Booster.R @@ -834,11 +834,15 @@ print.lgb.Booster <- function(x, ...) { } if (!handle_is_null) { + obj <- x$params$objective + if (obj == "none") { + obj <- "custom" + } if (x$.__enclos_env__$private$num_class == 1L) { - cat(sprintf("Objective: %s\n", x$params$objective)) + cat(sprintf("Objective: %s\n", obj)) } else { cat(sprintf("Objective: %s (%d classes)\n" - , x$params$objective + , obj , x$.__enclos_env__$private$num_class)) } } else { diff --git a/R-package/tests/testthat/test_lgb.Booster.R b/R-package/tests/testthat/test_lgb.Booster.R index 51cacfa81eab..c5b328c82973 100644 --- a/R-package/tests/testthat/test_lgb.Booster.R +++ b/R-package/tests/testthat/test_lgb.Booster.R @@ -1086,6 +1086,40 @@ test_that("Booster's print, show, and summary work correctly", { , nrounds = 5L ) .check_methods_work(model) + + + # with custom objective + .logregobj <- function(preds, dtrain) { + labels <- get_field(dtrain, "label") + preds <- 1.0 / (1.0 + exp(-preds)) + grad <- preds - labels + hess <- preds * (1.0 - preds) + return(list(grad = grad, hess = hess)) + } + + .evalerror <- function(preds, dtrain) { + labels <- get_field(dtrain, "label") + preds <- 1.0 / (1.0 + exp(-preds)) + err <- as.numeric(sum(labels != (preds > 0.5))) / length(labels) + return(list( + name = "error" + , value = err + , higher_better = FALSE + )) + } + + model <- lgb.train( + data = lgb.Dataset( + as.matrix(iris[, -5L]) + , label = as.numeric(iris$Species == "virginica") + ) + , obj = .logregobj + , eval = .evalerror + , verbose = 0L + , nrounds = 5L + ) + + .check_methods_work(model) }) test_that("LGBM_BoosterGetNumFeature_R returns correct outputs", { From f4334010a69dc9275f1e2efd07e0c1badd114bd4 Mon Sep 17 00:00:00 2001 From: David Cortes Date: Tue, 26 Oct 2021 12:55:15 -0300 Subject: [PATCH 16/17] linter --- R-package/tests/testthat/test_lgb.Booster.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R-package/tests/testthat/test_lgb.Booster.R b/R-package/tests/testthat/test_lgb.Booster.R index c5b328c82973..f42d3ff8cf1e 100644 --- a/R-package/tests/testthat/test_lgb.Booster.R +++ b/R-package/tests/testthat/test_lgb.Booster.R @@ -1037,7 +1037,7 @@ test_that("boosters with linear models at leaves can be written to RDS and re-lo }) test_that("Booster's print, show, and summary work correctly", { - .have_same_handle <- function(model, other_model){ + .have_same_handle <- function(model, other_model) { expect_equal( model$.__enclos_env__$private$handle , other_model$.__enclos_env__$private$handle From c749482bea08c651c7bfaacb4641832448001c72 Mon Sep 17 00:00:00 2001 From: David Cortes Date: Tue, 26 Oct 2021 14:30:10 -0300 Subject: [PATCH 17/17] linter --- R-package/tests/testthat/test_lgb.Booster.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R-package/tests/testthat/test_lgb.Booster.R b/R-package/tests/testthat/test_lgb.Booster.R index f42d3ff8cf1e..8e4b417a035f 100644 --- a/R-package/tests/testthat/test_lgb.Booster.R +++ b/R-package/tests/testthat/test_lgb.Booster.R @@ -1045,7 +1045,7 @@ test_that("Booster's print, show, and summary work correctly", { } .check_methods_work <- function(model) { - + # should work for fitted models ret <- print(model) .have_same_handle(ret, model)