-
-
Notifications
You must be signed in to change notification settings - Fork 8.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[New Feature] Monotonic Constraints in Tree Construction #1514
Comments
An experimental version is provided in #1516. To use this before it get merged, clone the repo https://github.com/tqchen/xgboost, Turn on the following options(likely possible via python, r API)
There are two arguments
Things to verify
Known limitationsCurrently only supported exact greedy algorithm on multi-core. Not yet available in distributed version |
@tqchen I got a request at work today to build some GBM's with monotone constraints to test vs. the performance of some other models. This would be with a tweedie deviance loss, so I would have to go with a custom loss function as it stands today. In any case, seems like a good chance to help out and get some work done at the same time. |
Based on the talk here, GBM(R Package) only enforces monotonicity locally. |
I do not understand what you mean by local or gloabl constrain, can you elaborate? |
Sorry, I paste wrong link, here is the right one (Link) |
OK, in my understanding, it is enforced globally. You are welcomed to try it out. |
Just did some simple tests of monotonicity constraint in the context of a univariate regression. You can find the code and some very brief documentation here: Some initial observations:
|
Turns out I introduce a bug in the constraint = -1 case. I pushed a fix, please see if newest version works well. Please also check if it works when there are multiple constraints |
@tqchen I tested your fix for the decresing bug, seems like it's working now. |
Let us confirm if there is speed decreasing vs the original version on some of the standard dataset, then we can merge it in |
@tqchen I tested a two variable model, one with an increasing constraint and one with a decreasing:
The results are good I'll try to find a little time to do some timing tests this afternoon. |
I made an update to #1516 to allow automatic detection of montone options, now user only need to pass in I will merge this in if the speed tests going OK, and let us move on to next stage of adding tutorials |
Added tests for the multivariate case here:
|
I ran a couple of timing experiments in a jupyter notebook. First test: some simple simulated data. There are two features, one increasing and one decreasing, but with a small sinusoidal wave superimposed so that each feature is not truly monotonic
Here are timing results from xgboosts with and without monotone constraints. I turned off early stopping and boosted a set number of iterations for each. First without monotone constraints:
And here with monotonicity constraints
Second test: California hHousing data from sklearn. Without constraints
Here are the constraints I used
And the timing for the constrained model
|
@XiaoxiaoWang87 I have pushed another PR to loose the check on wleft and wright, please see it it works. |
@tqchen Sure. Can you recommend a commit hash to compare against? Should I just use the commit prior to your addition of the monotone constraints? |
Yes the previous one will do |
@tqchen On rebuilding the updated version, I'm getting some errors that I was not having before. I'm hoping the reason jumps out at you clearly. If I try to run the same code as before, I'm getting an exception, here is the full traceback:
If I switch out everything for the keyword argument you implemented I also get an error:
|
remove the updater argument and keep the monotone constraint arguments in parameters, now that monotone constraint updater is activated automatically when monotone constraints are presented |
@madrury can you confirm the speed? |
Also @madrury and @XiaoxiaoWang87 since this feature is now close to be merged, it would be great if you can coordinate to create a tutorial introducing this feature to the users. We cannot directly take ipy notebook to the main repo. but images can be pushed to https://github.com/dmlc/web-data/tree/master/xgboost and markdown to main repo. |
We also need to change the front-end interface string conversion, so that int tuple can be converted into the string tuple format that can be accepted by the backend. @hetong007 for changes in R and @slundberg for Julia |
@tqchen Julia is currently attached to the 0.4 version of XGBoost so next time I need to use it and have time set aside I'll update the bindings if no one else has by then. At that point this change can also get added. |
Here's the comparison between models without a monotone constraint from before the implementation to afterwards. Commit 8cac37: Before implementation of monotone constraint.' Commit b1c224: After implementation of monotone constraint. The speedup for california after the implementation looks suspicious to me, but I tried it twice each way, and it's consistent. |
I'd be happy to take a shot at writing a tutorial. I'll look around at the existing documentation and put something together in the next few days. |
This is great, the PR is now officially merged to the master. Looking forward to see the tutorial |
Thanks @madrury. Look forward to it. Let me know what I can help. I'd be certainly willing to have more studies on this topic. |
I will enhance it tomorrow. I'm just curious about the reason of communicating with C++ via a string instead of an array. |
I am testing from R. I randomly generated a two-variable data and try to make prediction. However, I found that
Please point it out if I made any mistakes. The code to reproduce it (tested on the latest github version, not from set.seed(1024)
x1 = rnorm(1000, 10)
x2 = rnorm(1000, 10)
y = -1*x1 + rnorm(1000, 0.001) + 3*sin(x2)
train = cbind(x1, x2)
bst = xgboost(data = train, label = y, max_depth = 2,
eta = 0.1, nthread = 2, nrounds = 10,
monotone_constraints = '(1,-1)')
pred = predict(bst, train)
ind = order(train[,1])
pred.ord = pred[ind]
plot(train[,1], y, main = 'with constraint')
pred.ord = pred[order(train[,1])]
lines(pred.ord) bst = xgboost(data = train, label = y, max_depth = 2,
eta = 0.1, nthread = 2, nrounds = 10)
pred = predict(bst, train)
ind = order(train[,1])
pred.ord = pred[ind]
plot(train[,1], y, main = 'without constraint')
pred.ord = pred[order(train[,1])]
lines(pred.ord) |
The constraint was done on the partial order. So constraint is only enforced if we are moving the montone axis, keeping other axis fixed |
@hetong007 To make my plots I
Here's the python code that I used for the plots I included above, it should pretty easily convert to equivalent R code.
|
Here is how I do the partial dependence plots (for an arbitrary model):
Code:
|
Thanks for the guidance! I realized that I made a silly mistake in the plot. Here's another test on an univariate data, the plot seems fine: set.seed(1024)
x = rnorm(1000, 10)
y = -1*x + rnorm(1000, 0.001) + 3*sin(x)
train = matrix(x, ncol = 1)
bst = xgboost(data = train, label = y, max_depth = 2,
eta = 0.1, nthread = 2, nrounds = 100,
monotone_constraints = '(-1)')
pred = predict(bst, train)
ind = order(train[,1])
pred.ord = pred[ind]
plot(train[,1], y, main = 'with constraint', pch=20)
lines(train[ind,1], pred.ord, col=2, lwd = 5) bst = xgboost(data = train, label = y, max_depth = 2,
eta = 0.1, nthread = 2, nrounds = 100)
pred = predict(bst, train)
ind = order(train[,1])
pred.ord = pred[ind]
plot(train[,1], y, main = 'without constraint', pch=20)
lines(train[ind,1], pred.ord, col=2, lwd = 5) |
@hetong007 So the goal in R interface is to enable user to pass in R array besides the strings monotone_constraints=c(1,-1) |
Please let us know when you are PR the tutorial @hetong007 You are also more than welcomed to make a r-blogger version |
@tqchen Sorry guys, I've been on a work trip for the week. I sent a couple of pull requests with for a monotonic constraint tutorial. Please let me know what you think, I'm happy with any criticism or critique. |
Hopefully it is appropriate to ask this here: will this now work if we update using the usual I ask as I saw the new tutorial out but nothing new about a change to the code itself. Thank you all! |
yes, the new feature is merged before the tutorial get merged |
Hello, I'm not sure that you succesfully implemented global montonicity, from what i've seen in your code, it corresponds more to a local monotonicity. Here is a simple example breaking monotonicity : ` library(xgboost) sans_corr <- data.frame(x1=c(1,2,1,2),x2=c(1,1,2,2)) sans_corr$prediction <- predict(XGB,data.matrix(sans_corr)) Hope my understanding of your code and my example is not false |
Currently this feature is not in the Sklearn api. Can you or someone please help to add it? Thanks! |
It is possible to enforce general monotonicity on a variable, without specifying whether it should be increasing or decreasing? |
@davidADSP you can do a spearman correlation check on the desired predictor and target to see whether increasing or decreasing is proper. |
This feature seems to be invalid when 'tree_method':'hist'. @tqchen any help? Thanks all. |
How does the constraint work for multiclass objective like mlogloss? Is monotonicity constraint supported for multiclass loss? If yes, how is it enforced. (As for each class there is a tree) |
Is there any whitepaper on Monoticity Algorithm enforced in XGBOOST ? Is it Global or Local? Local means specific to certain nodes but nodes in other parts of the tree might create a violation of the overall monotonicity. Also can anyone please help me in understanding line L412-417. Why "w" is bounded- upper and lower. How this helps to maintain Monotonicity. Line 457 - Why "mid" is used? |
I got a few requests on supporting monotonic constraints on certain feature with respect to the output,
i.e. when other features are fixed, force the prediction to be monotonic increasing with respect to the the certain specified feature. I am opening this issue to see the general interest on this feature. I can add this if there is enough interest on this,
I would need help from volunteers from the community to test the beta feature and contribute document and tutorial on using this feature. Please reply the issue if you are interested
The text was updated successfully, but these errors were encountered: