dmlc / dmlc/xgboost

'scale_pos_weight' parameter

Open
#8,184 2 comments 4 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
28.8k
Forks
8.9k
Avg merge
1d 12h
Merged PRs (30d)
54

Description

I want to use this issue to document some pitfalls of the 'scale_pos_weight' parameter and discuss if it needs to be changed or documented better. The following script illustrates some different scenarios and the way that training loss is reported. Each of the models is exactly the same but the reported training loss metric can be different.

In particular, for this example, if the weights for the evaluation part are not adjusted we can see the training loss diverge even when training is proceeding correctly. To compensate for this the user should manually generate sample_weights for the eval matrix that exactly match the weights produced by 'scale_pos_weight'. It may not be immediately clear to the user what 'scale_pos_weight' is doing behind the scenes and that it is exactly equivalent to applying sample weights as below.

Given that sklearn has the nice function `compute_sample_weight` that can perform the same task in a more obvious way, maybe 'scale_pos_weight' should be deprecated and documentation examples added that instead directly modify weights to deal with imbalanced class problems.

```python
from sklearn.utils.class_weight import compute_sample_weight
import xgboost as xgb
import numpy as np

np.random.seed(0)
X = np.random.random((1000, 10))
y = np.random.binomial(1, 0.5, X.shape[0])
scale_pos_weight = 1000
print("Sklearn interface using scale_pos_weight")
xgb.XGBClassifier(n_estimators=5, max_depth=1, scale_pos_weight=scale_pos_weight).fit(
X, y, eval_set=[(X, y)]
)

print("Sklearn interface using sample weights for training")
sample_weight = compute_sample_weight({0: 1.0, 1: scale_pos_weight}, y)
xgb.XGBClassifier(n_estimators=5, max_depth=1).fit(
X, y, eval_set=[(X, y)], sample_weight=sample_weight
)

print("Sklearn interface using sample weights for training and eval")
sample_weight = compute_sample_weight({0: 1.0, 1: scale_pos_weight}, y)
xgb.XGBClassifier(n_estimators=5, max_depth=1).fit(
X,
y,
eval_set=[(X, y)],
sample_weight=sample_weight,
sample_weight_eval_set=[sample_weight],
)

print("Xgb interface using scale_pos_weight")
dtrain = xgb.DMatrix(X, y)
param = {
"objective": "binary:logistic",
"max_depth": 1,
"learning_rate": 0.3,
}
xgb.train(
{"scale_pos_weight": scale_pos_weight, **param},
dtrain,
5,
evals=[(dtrain, "train")],
)

print("Xgb interface using dmatrix sample weights")
dtrain_weighted = xgb.DMatrix(X, y, weight=sample_weight)
xgb.train(
param,
dtrain_weighted,
5,
evals=[(dtrain_weighted, "train")],
)

```

```
Sklearn interface using scale_pos_weight
[0] validation_0-logloss:0.75272
[1] validation_0-logloss:0.85645
[2] validation_0-logloss:0.97991
[3] validation_0-logloss:1.11445
[4] validation_0-logloss:1.25575
Sklearn interface using sample weights for training
[0] validation_0-logloss:0.75272
[1] validation_0-logloss:0.85645
[2] validation_0-logloss:0.97991
[3] validation_0-logloss:1.11445
[4] validation_0-logloss:1.25575
Sklearn interface using sample weights for training and eval
[0] validation_0-logloss:0.43863
[1] validation_0-logloss:0.29814
[2] validation_0-logloss:0.20971
[3] validation_0-logloss:0.15066
[4] validation_0-logloss:0.10990
Xgb interface using scale_pos_weight
[0] train-logloss:0.75272
[1] train-logloss:0.85645
[2] train-logloss:0.97991
[3] train-logloss:1.11445
[4] train-logloss:1.25575
Xgb interface using dmatrix sample weights
[0] train-logloss:0.43863
[1] train-logloss:0.29814
[2] train-logloss:0.20971
[3] train-logloss:0.15066
[4] train-logloss:0.10990
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by running the Python reproducer and comparing the sklearn interface with xgb.train, using scale_pos_weight, sample_weight, and sample_weight_eval_set. Read the existing parameter documentation and metric-reporting guidance; done means the weighting behavior and evaluation-loss implications are clearly documented, or the deprecation question has a recorded decision.

Written by the indexing model from the issue text.

Assessment

Tech stack
numpy, python, scikit-learn
Domain
documentation, machine-learning
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.