Skip to content

Commit

Permalink
[R-package] add docs and tests on monotone constraints (fixes #4345)
Browse files Browse the repository at this point in the history
  • Loading branch information
jameslamb committed Jun 7, 2021
1 parent 20e6338 commit 687390f
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 0 deletions.
125 changes: 125 additions & 0 deletions R-package/tests/testthat/test_basic.R
Original file line number Diff line number Diff line change
Expand Up @@ -2042,3 +2042,128 @@ test_that(paste0("lgb.train() gives same results when using interaction_constrai
expect_equal(pred1, pred2)

})

context("monotone constraints")

.generate_trainset_for_monotone_constraints_tests <- function(x3_to_categorical) {
n_samples <- 3000L
x1_positively_correlated_with_y <- rnorm(n = n_samples)
x2_negatively_correlated_with_y <- rnorm(n = n_samples)
x3_negatively_correlated_with_y <- rnorm(n = n_samples)
if (x3_to_categorical) {
x3_negatively_correlated_with_y <- as.integer(abs(runif(n_samples) / 0.25))
categorical_features <- 3L
} else {
x3_negatively_correlated_with_y <- runif(n_samples)
categorical_features <- NULL
}
X <- data.matrix(
data.frame(
list(
x1_positively_correlated_with_y
, x2_negatively_correlated_with_y
, x3_negatively_correlated_with_y
)
)
)
zs <- rnorm(n = n_samples, mean = 0.0, sd = 0.01)
scales <- 10.0 * rnorm(6L + 0.5)
y <- (
scales[1L] * x1_positively_correlated_with_y
+ sin(scales[2L] * pi * x1_positively_correlated_with_y)
- scales[3L] * x2_negatively_correlated_with_y
- cos(scales[4L] * pi * x2_negatively_correlated_with_y)
- scales[5L] * x3_negatively_correlated_with_y
- cos(scales[6L] * pi * x3_negatively_correlated_with_y)
+ zs
)
return(lgb.Dataset(
data = X
, label = y
, categorical_feature = categorical_features
, free_raw_data = FALSE
))
}

.is_increasing <- function(y) {
return(all(diff(y) >= 0.0))
}

.is_decreasing <- function(y) {
return(all(diff(y) <= 0.0))
}

.is_non_monotone <- function(y) {
return(any(diff(y) < 0.0) & any(diff(y) > 0.0))
}

.is_correctly_constrained <- function(learner, x3_to_category) {
iterations <- 10L
n <- 1000L
variable_x <- seq_len(n) / n
fixed_xs_values <- seq_len(n)
for (i in seq_len(iterations)) {
monotonically_increasing_x <- data.matrix(
data.frame(
list(variable_x, fixed_x, fixed_x)
)
)
monotonically_increasing_y <- predict(learner, monotonically_increasing_x)

monotonically_decreasing_x <- data.matrix(
data.frame(
list(fixed_x, variable_x, fixed_x)
)
)
monotonically_decreasing_y <- predict(learner, monotonically_decreasing_x)

non_monotone_x <- data.matrix(
data.frame(
list(
fixed_x
, fixed_x
)
)
)

}
}

for (x3_to_categorical in c(TRUE, FALSE)){
for (monotone_constraints_method in c("basic", "intermediate", "advanced")) {
test_msg <- paste0(
"lgb.train() supports monotone constraints ("
, "categoricals="
, x3_to_categorical
, ", method="
, monotone_constraints_method
, ")"
)
test_that(test_msg, {
set.seed(708L)
dtrain <- .generate_trainset_for_monotone_constraints_tests(
x3_to_categorical = x3_to_categorical
)
params <- list(
min_data = 20L
, num_leaves = 20L
, use_missing = FALSE
)
unconstrained_model <- lgb.train(
params = params
, data = dtrain
, obj = "regression_l2"
, nrounds = 10L
)
params[["monotone_constraints"]] <- c(1L, -1L, 0L)
params[["monotone_constraints_method"]] <- monotone_constraints_method
constrained_model <- lgb.train(
params = params
, data = dtrain
, obj = "regression_l2"
, nrounds = 10L
)
X <- dtrain$.__enclos_env__$private$raw_data
})
}
}
6 changes: 6 additions & 0 deletions docs/Parameters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,12 @@ Learning Control Parameters

- you need to specify all features in order. For example, ``mc=-1,0,1`` means decreasing for 1st feature, non-constraint for 2nd feature and increasing for the 3rd feature

- in the CLI or C++, use a string like ``"-1,0,1"``

- in the Python package, can use either a string or a list like ``[-1, 0, 1]``

- in the R package, can use either a string or a vector like ``c(-1, 0, 1)``

- ``monotone_constraints_method`` :raw-html:`<a id="monotone_constraints_method" title="Permalink to this parameter" href="#monotone_constraints_method">&#x1F517;&#xFE0E;</a>`, default = ``basic``, type = enum, options: ``basic``, ``intermediate``, ``advanced``, aliases: ``monotone_constraining_method``, ``mc_method``

- used only if ``monotone_constraints`` is set
Expand Down
3 changes: 3 additions & 0 deletions include/LightGBM/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,9 @@ struct Config {
// desc = used for constraints of monotonic features
// desc = ``1`` means increasing, ``-1`` means decreasing, ``0`` means non-constraint
// desc = you need to specify all features in order. For example, ``mc=-1,0,1`` means decreasing for 1st feature, non-constraint for 2nd feature and increasing for the 3rd feature
// desc = in the CLI or C++, use a string like ``"-1,0,1"``
// desc = in the Python package, can use either a string or a list like ``[-1, 0, 1]``
// desc = in the R package, can use either a string or a vector like ``c(-1, 0, 1)``
std::vector<int8_t> monotone_constraints;

// type = enum
Expand Down

0 comments on commit 687390f

Please sign in to comment.