preorder4mlc 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- preorder4mlc-1.0.0/CITATION.cff +57 -0
- preorder4mlc-1.0.0/LICENSE +21 -0
- preorder4mlc-1.0.0/MANIFEST.in +8 -0
- preorder4mlc-1.0.0/PKG-INFO +213 -0
- preorder4mlc-1.0.0/README.md +155 -0
- preorder4mlc-1.0.0/REPRODUCE.md +192 -0
- preorder4mlc-1.0.0/docs/CONVENTIONS.md +9 -0
- preorder4mlc-1.0.0/docs/EXTENDING.md +19 -0
- preorder4mlc-1.0.0/docs/RELEASE_CHECKLIST.md +24 -0
- preorder4mlc-1.0.0/docs/REPRODUCING.md +31 -0
- preorder4mlc-1.0.0/docs/paper.yaml +30 -0
- preorder4mlc-1.0.0/preorder4mlc/__init__.py +4 -0
- preorder4mlc-1.0.0/preorder4mlc/base_classifiers.py +242 -0
- preorder4mlc-1.0.0/preorder4mlc/config.py +115 -0
- preorder4mlc-1.0.0/preorder4mlc/constants.py +30 -0
- preorder4mlc-1.0.0/preorder4mlc/datasets4experiments.py +176 -0
- preorder4mlc-1.0.0/preorder4mlc/estimator.py +123 -0
- preorder4mlc-1.0.0/preorder4mlc/evaluation_metric.py +888 -0
- preorder4mlc-1.0.0/preorder4mlc/inference_models.py +502 -0
- preorder4mlc-1.0.0/preorder4mlc/searching_algorithms.py +517 -0
- preorder4mlc-1.0.0/preorder4mlc/solvers.py +178 -0
- preorder4mlc-1.0.0/preorder4mlc/training_orchestrator.py +474 -0
- preorder4mlc-1.0.0/preorder4mlc/utils/plot_figures.py +1014 -0
- preorder4mlc-1.0.0/preorder4mlc/utils/results_manager.py +167 -0
- preorder4mlc-1.0.0/preorder4mlc/utils/statistical_tests.py +411 -0
- preorder4mlc-1.0.0/preorder4mlc/utils/summarize_metrics.py +250 -0
- preorder4mlc-1.0.0/preorder4mlc/utils/suppress.py +55 -0
- preorder4mlc-1.0.0/preorder4mlc.egg-info/PKG-INFO +213 -0
- preorder4mlc-1.0.0/preorder4mlc.egg-info/SOURCES.txt +35 -0
- preorder4mlc-1.0.0/preorder4mlc.egg-info/dependency_links.txt +1 -0
- preorder4mlc-1.0.0/preorder4mlc.egg-info/requires.txt +22 -0
- preorder4mlc-1.0.0/preorder4mlc.egg-info/top_level.txt +1 -0
- preorder4mlc-1.0.0/pyproject.toml +101 -0
- preorder4mlc-1.0.0/requirements-core.txt +10 -0
- preorder4mlc-1.0.0/requirements.txt +13 -0
- preorder4mlc-1.0.0/setup.cfg +4 -0
- preorder4mlc-1.0.0/tests/test_smoke.py +13 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Citation File Format - https://citation-file-format.github.io/
|
|
2
|
+
cff-version: 1.2.0
|
|
3
|
+
title: "preorder4MLC: Pre-Order Based Multi-Label Classification"
|
|
4
|
+
message: "If you use this software, please cite the accompanying paper."
|
|
5
|
+
type: software
|
|
6
|
+
authors:
|
|
7
|
+
- family-names: Hoang
|
|
8
|
+
given-names: Xuan-Truong
|
|
9
|
+
email: hxtruong@jaist.ac.jp
|
|
10
|
+
affiliation: "School of Knowledge Science, Japan Advanced Institute of Science and Technology, Japan"
|
|
11
|
+
orcid: "https://orcid.org/0009-0003-4350-5148"
|
|
12
|
+
- family-names: Nguyen
|
|
13
|
+
given-names: Vu-Linh
|
|
14
|
+
email: vu-linh.nguyen@hds.utc.fr
|
|
15
|
+
affiliation: "Heudiasyc Laboratory, University of Technology of Compiègne, France"
|
|
16
|
+
- family-names: Destercke
|
|
17
|
+
given-names: Sébastien
|
|
18
|
+
email: sebastien.destercke@hds.utc.fr
|
|
19
|
+
affiliation: "Heudiasyc Laboratory, University of Technology of Compiègne, France"
|
|
20
|
+
- family-names: de Campos
|
|
21
|
+
given-names: Cassio
|
|
22
|
+
email: c.decampos@tue.nl
|
|
23
|
+
affiliation: "Uncertainty in Artificial Intelligence Group, Eindhoven University of Technology, The Netherlands"
|
|
24
|
+
- family-names: Huynh
|
|
25
|
+
given-names: Van-Nam
|
|
26
|
+
email: huynh@jaist.ac.jp
|
|
27
|
+
affiliation: "School of Knowledge Science, Japan Advanced Institute of Science and Technology, Japan"
|
|
28
|
+
repository-code: "https://github.com/hxtruong6/pre-order-for-mlc"
|
|
29
|
+
license: MIT
|
|
30
|
+
version: "1.0.0"
|
|
31
|
+
date-released: "2026-05-15"
|
|
32
|
+
keywords:
|
|
33
|
+
- multi-label classification
|
|
34
|
+
- preference learning
|
|
35
|
+
- noisy and imbalanced labels
|
|
36
|
+
- robustness
|
|
37
|
+
- partial-abstention
|
|
38
|
+
- integer linear programming
|
|
39
|
+
preferred-citation:
|
|
40
|
+
type: article
|
|
41
|
+
title: "Robust Multi-Label Classification via Preference Learning"
|
|
42
|
+
authors:
|
|
43
|
+
- family-names: Hoang
|
|
44
|
+
given-names: Xuan-Truong
|
|
45
|
+
orcid: "https://orcid.org/0009-0003-4350-5148"
|
|
46
|
+
- family-names: Nguyen
|
|
47
|
+
given-names: Vu-Linh
|
|
48
|
+
- family-names: Destercke
|
|
49
|
+
given-names: Sébastien
|
|
50
|
+
- family-names: de Campos
|
|
51
|
+
given-names: Cassio
|
|
52
|
+
- family-names: Huynh
|
|
53
|
+
given-names: Van-Nam
|
|
54
|
+
journal: "Machine Learning"
|
|
55
|
+
publisher: "Springer"
|
|
56
|
+
year: 2026
|
|
57
|
+
doi: "<TODO: DOI once assigned>"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hoàng Xuân Trường and Vu-Linh Nguyen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: preorder4mlc
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Robust multi-label classification via preference learning: pairwise classifiers and ILP-based Bayes-optimal order-structure prediction.
|
|
5
|
+
Author-email: Xuan-Truong Hoang <hxtruong@jaist.ac.jp>, Vu-Linh Nguyen <vu-linh.nguyen@hds.utc.fr>, Sébastien Destercke <sebastien.destercke@hds.utc.fr>, Cassio de Campos <c.decampos@tue.nl>, Van-Nam Huynh <huynh@jaist.ac.jp>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Hoàng Xuân Trường and Vu-Linh Nguyen
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Repository, https://github.com/hxtruong6/pre-order-for-mlc
|
|
29
|
+
Keywords: multi-label classification,preference learning,order structures,integer linear programming,partial abstention,robustness
|
|
30
|
+
Classifier: Programming Language :: Python :: 3
|
|
31
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
32
|
+
Classifier: Intended Audience :: Science/Research
|
|
33
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
34
|
+
Requires-Python: >=3.10
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
License-File: LICENSE
|
|
37
|
+
Requires-Dist: numpy>=1.26
|
|
38
|
+
Requires-Dist: scipy>=1.12
|
|
39
|
+
Requires-Dist: scikit-learn>=1.4
|
|
40
|
+
Requires-Dist: pandas>=2.0
|
|
41
|
+
Requires-Dist: joblib>=1.3
|
|
42
|
+
Requires-Dist: liac-arff>=2.5
|
|
43
|
+
Requires-Dist: lightgbm>=4.0
|
|
44
|
+
Requires-Dist: highspy>=1.7
|
|
45
|
+
Requires-Dist: cvxopt>=1.3
|
|
46
|
+
Requires-Dist: scikit-multilearn>=0.2
|
|
47
|
+
Provides-Extra: viz
|
|
48
|
+
Requires-Dist: matplotlib>=3.8; extra == "viz"
|
|
49
|
+
Requires-Dist: seaborn>=0.13; extra == "viz"
|
|
50
|
+
Requires-Dist: openpyxl>=3.1; extra == "viz"
|
|
51
|
+
Provides-Extra: dev
|
|
52
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
53
|
+
Requires-Dist: pytest-cov>=4; extra == "dev"
|
|
54
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
55
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
56
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
57
|
+
Dynamic: license-file
|
|
58
|
+
|
|
59
|
+
# preorder4MLC: Pre-Order Based Multi-Label Classification
|
|
60
|
+
|
|
61
|
+
[](LICENSE)
|
|
62
|
+
[](https://www.python.org/)
|
|
63
|
+
|
|
64
|
+
In **multi-label classification (MLC)** each instance can carry several
|
|
65
|
+
labels at once (a song that is both *happy* and *relaxed* — as in the
|
|
66
|
+
`emotions` dataset; an email tagged both *business* and *legal* — as in the
|
|
67
|
+
`enron` dataset, both used in this paper). This repository introduces a method that predicts
|
|
68
|
+
labels by first learning **how labels compare** rather than deciding each
|
|
69
|
+
label in isolation — and that can **abstain** on labels it is unsure about
|
|
70
|
+
instead of guessing.
|
|
71
|
+
|
|
72
|
+
> 📄 Code and full experimental results for:
|
|
73
|
+
> **Robust Multi-Label Classification via Preference Learning** —
|
|
74
|
+
> Vu-Linh Nguyen, Xuan-Truong Hoang, Sébastien Destercke, Cassio de Campos,
|
|
75
|
+
> Van-Nam Huynh (Nguyen and Hoang contributed equally).
|
|
76
|
+
> *Machine Learning* (Springer), 2026. \<TODO: DOI once assigned\>
|
|
77
|
+
|
|
78
|
+
> **Abstract.** We explore how multi-label classification (MLC) tasks can
|
|
79
|
+
> be cast into order structure learning, exploiting the rich structure of
|
|
80
|
+
> orders to improve and robustify MLC. We formalise the transformation of
|
|
81
|
+
> MLC into an order structure learning and prediction task, study the
|
|
82
|
+
> prediction of Bayes-optimal order structures, and run experiments in
|
|
83
|
+
> settings where orders are especially beneficial: robust MLC under noisy
|
|
84
|
+
> and imbalanced labels, and MLC prediction with partial abstention.
|
|
85
|
+
|
|
86
|
+
## What it does
|
|
87
|
+
|
|
88
|
+
The method is built around **Bipartite Ordered Preference Orders (BOPOs)**.
|
|
89
|
+
Instead of predicting each label independently, it works in three steps:
|
|
90
|
+
|
|
91
|
+
1. **Learn pairwise preferences.** For every pair of labels, a calibrated
|
|
92
|
+
classifier estimates the probability of their relative ordering.
|
|
93
|
+
2. **Search for the best order.** Per instance, an integer linear program
|
|
94
|
+
(ILP) combines those pairwise probabilities into a single coherent
|
|
95
|
+
**preference order** — a *pre-order* or a *partial-order* — that
|
|
96
|
+
minimises an expected loss (Hamming or Subset 0/1).
|
|
97
|
+
3. **Derive a prediction.** The order is turned into one of three outputs:
|
|
98
|
+
a plain binary vector, the preference order itself, or a
|
|
99
|
+
**partial-abstention** vector that marks uncertain labels as "abstain".
|
|
100
|
+
|
|
101
|
+
An optional *height* constraint on the order yields **eight inference
|
|
102
|
+
algorithms** in total (pre-/partial-order × Hamming/Subset × height 2/∅).
|
|
103
|
+
We compare against four standard baselines: **BR, CC, CLR, ECC**.
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
┌──────────────────────┐
|
|
107
|
+
training → │ K(K−1)/2 pairwise │ → pairwise probabilities pᵢⱼ
|
|
108
|
+
│ calibrated classif. │
|
|
109
|
+
└──────────────────────┘
|
|
110
|
+
│
|
|
111
|
+
▼
|
|
112
|
+
┌──────────────────────┐
|
|
113
|
+
│ per-instance ILP │ → preference order
|
|
114
|
+
│ search (cvxopt+GLPK) │ (pre- or partial-order)
|
|
115
|
+
└──────────────────────┘
|
|
116
|
+
│
|
|
117
|
+
▼
|
|
118
|
+
┌──────────────────────┐
|
|
119
|
+
│ derive prediction │ → BinaryVector
|
|
120
|
+
│ │ PreferenceOrder
|
|
121
|
+
│ │ PartialAbstention
|
|
122
|
+
└──────────────────────┘
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Quick start
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Install (editable, so scripts/ can import the package)
|
|
129
|
+
python -m venv .venv && source .venv/bin/activate
|
|
130
|
+
pip install -r requirements.txt
|
|
131
|
+
pip install -e .
|
|
132
|
+
|
|
133
|
+
# Run one dataset end-to-end
|
|
134
|
+
python scripts/train.py --dataset emotions --results_dir results/run-dev
|
|
135
|
+
python scripts/evaluate.py --dataset emotions --results_dir results/run-dev
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
To reproduce **every** number and figure in the paper, see
|
|
139
|
+
[REPRODUCE.md](REPRODUCE.md) — it covers the full pipeline, expected wall
|
|
140
|
+
times, and the exact environment.
|
|
141
|
+
|
|
142
|
+
## Datasets
|
|
143
|
+
|
|
144
|
+
Ten multi-label datasets are used:
|
|
145
|
+
`chd_49`, `emotions`, `scene`, `yeast`, `water_quality`, `humanpseaac`,
|
|
146
|
+
`gpositivepseaac`, `plantpseaac`, `viruspseaac`, and `enron`.
|
|
147
|
+
|
|
148
|
+
The first nine ARFFs are bundled under `data/`, so the pipeline runs
|
|
149
|
+
end-to-end right after `pip install`. `enron.arff` (K=53) is downloaded
|
|
150
|
+
separately — see [REPRODUCE.md §2](REPRODUCE.md). CLI keys match
|
|
151
|
+
`preorder4mlc.config::ConfigManager.DATASET_CONFIGS`.
|
|
152
|
+
|
|
153
|
+
## Partial abstention
|
|
154
|
+
|
|
155
|
+
A partial-abstention prediction is a vector in `{0, 1, −1}` where `−1`
|
|
156
|
+
means **"abstain"** on that label. This lets the model stay silent where
|
|
157
|
+
it is uncertain instead of forcing a 0/1 call. Two pairs of metrics
|
|
158
|
+
capture the trade-off — *recovery* (did the abstentions cover the truth?)
|
|
159
|
+
and *abstention rate* (how often did it abstain?):
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
ŷ = [1, 0, 1, −1, 0, −1] y = [0, 0, 1, 1, 0, 0]
|
|
163
|
+
|
|
164
|
+
AREC = (0 + 1 + 1 + 1 + 1 + 1) / 6 = 4/6 # −1 counts as covering {0,1}
|
|
165
|
+
AABS = 2 / 6 # fraction abstained
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Full definitions (`AREC`, `AABS`, `REC`, `ABS`) live in
|
|
169
|
+
`preorder4mlc.evaluation_metric`.
|
|
170
|
+
|
|
171
|
+
## Repository layout
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
preorder4mlc/ # Library package
|
|
175
|
+
├── config.py # Run configuration + dataset registry
|
|
176
|
+
├── datasets4experiments.py # ARFF loading, k-fold splits, label noise
|
|
177
|
+
├── base_classifiers.py # Pairwise / calibrated classifier factory
|
|
178
|
+
├── estimator.py # Uniform interface over RF / ETC / XGBoost / LightGBM
|
|
179
|
+
├── inference_models.py # PredictBOPOs (BOPOs + BR / CC / CLR baselines)
|
|
180
|
+
├── searching_algorithms.py # ILP search for pre- and partial-orders
|
|
181
|
+
├── training_orchestrator.py # Training loop over learners × folds × algorithms
|
|
182
|
+
├── evaluation_metric.py # Example-, label-, ranking-, abstention-metrics
|
|
183
|
+
└── utils/ # Summaries, statistical tests, figures
|
|
184
|
+
|
|
185
|
+
scripts/ # CLI entry points
|
|
186
|
+
├── train.py / evaluate.py # BOPOs + CLR / BR / CC
|
|
187
|
+
├── train_ecc.py / evaluate_ecc.py # ECC baseline
|
|
188
|
+
└── smoke_predict_bopos.py # Behavior-preservation smoke test
|
|
189
|
+
|
|
190
|
+
data/ # 9 bundled ARFFs (enron downloaded separately)
|
|
191
|
+
results/ # Per-fold CSVs + aggregated tables
|
|
192
|
+
run.sh # End-to-end reproduction driver
|
|
193
|
+
REPRODUCE.md # Step-by-step reproduction recipe
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Citation
|
|
197
|
+
|
|
198
|
+
If you use this code, please cite the paper (see
|
|
199
|
+
[CITATION.cff](CITATION.cff)):
|
|
200
|
+
|
|
201
|
+
```bibtex
|
|
202
|
+
@article{nguyen2026robust,
|
|
203
|
+
title = {Robust Multi-Label Classification via Preference Learning},
|
|
204
|
+
author = {Nguyen, Vu-Linh and Hoang, Xuan-Truong and Destercke, S{\'e}bastien and de Campos, Cassio and Huynh, Van-Nam},
|
|
205
|
+
journal = {Machine Learning},
|
|
206
|
+
publisher = {Springer},
|
|
207
|
+
year = {2026},
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
Released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# preorder4MLC: Pre-Order Based Multi-Label Classification
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](https://www.python.org/)
|
|
5
|
+
|
|
6
|
+
In **multi-label classification (MLC)** each instance can carry several
|
|
7
|
+
labels at once (a song that is both *happy* and *relaxed* — as in the
|
|
8
|
+
`emotions` dataset; an email tagged both *business* and *legal* — as in the
|
|
9
|
+
`enron` dataset, both used in this paper). This repository introduces a method that predicts
|
|
10
|
+
labels by first learning **how labels compare** rather than deciding each
|
|
11
|
+
label in isolation — and that can **abstain** on labels it is unsure about
|
|
12
|
+
instead of guessing.
|
|
13
|
+
|
|
14
|
+
> 📄 Code and full experimental results for:
|
|
15
|
+
> **Robust Multi-Label Classification via Preference Learning** —
|
|
16
|
+
> Vu-Linh Nguyen, Xuan-Truong Hoang, Sébastien Destercke, Cassio de Campos,
|
|
17
|
+
> Van-Nam Huynh (Nguyen and Hoang contributed equally).
|
|
18
|
+
> *Machine Learning* (Springer), 2026. \<TODO: DOI once assigned\>
|
|
19
|
+
|
|
20
|
+
> **Abstract.** We explore how multi-label classification (MLC) tasks can
|
|
21
|
+
> be cast into order structure learning, exploiting the rich structure of
|
|
22
|
+
> orders to improve and robustify MLC. We formalise the transformation of
|
|
23
|
+
> MLC into an order structure learning and prediction task, study the
|
|
24
|
+
> prediction of Bayes-optimal order structures, and run experiments in
|
|
25
|
+
> settings where orders are especially beneficial: robust MLC under noisy
|
|
26
|
+
> and imbalanced labels, and MLC prediction with partial abstention.
|
|
27
|
+
|
|
28
|
+
## What it does
|
|
29
|
+
|
|
30
|
+
The method is built around **Bipartite Ordered Preference Orders (BOPOs)**.
|
|
31
|
+
Instead of predicting each label independently, it works in three steps:
|
|
32
|
+
|
|
33
|
+
1. **Learn pairwise preferences.** For every pair of labels, a calibrated
|
|
34
|
+
classifier estimates the probability of their relative ordering.
|
|
35
|
+
2. **Search for the best order.** Per instance, an integer linear program
|
|
36
|
+
(ILP) combines those pairwise probabilities into a single coherent
|
|
37
|
+
**preference order** — a *pre-order* or a *partial-order* — that
|
|
38
|
+
minimises an expected loss (Hamming or Subset 0/1).
|
|
39
|
+
3. **Derive a prediction.** The order is turned into one of three outputs:
|
|
40
|
+
a plain binary vector, the preference order itself, or a
|
|
41
|
+
**partial-abstention** vector that marks uncertain labels as "abstain".
|
|
42
|
+
|
|
43
|
+
An optional *height* constraint on the order yields **eight inference
|
|
44
|
+
algorithms** in total (pre-/partial-order × Hamming/Subset × height 2/∅).
|
|
45
|
+
We compare against four standard baselines: **BR, CC, CLR, ECC**.
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
┌──────────────────────┐
|
|
49
|
+
training → │ K(K−1)/2 pairwise │ → pairwise probabilities pᵢⱼ
|
|
50
|
+
│ calibrated classif. │
|
|
51
|
+
└──────────────────────┘
|
|
52
|
+
│
|
|
53
|
+
▼
|
|
54
|
+
┌──────────────────────┐
|
|
55
|
+
│ per-instance ILP │ → preference order
|
|
56
|
+
│ search (cvxopt+GLPK) │ (pre- or partial-order)
|
|
57
|
+
└──────────────────────┘
|
|
58
|
+
│
|
|
59
|
+
▼
|
|
60
|
+
┌──────────────────────┐
|
|
61
|
+
│ derive prediction │ → BinaryVector
|
|
62
|
+
│ │ PreferenceOrder
|
|
63
|
+
│ │ PartialAbstention
|
|
64
|
+
└──────────────────────┘
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Quick start
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Install (editable, so scripts/ can import the package)
|
|
71
|
+
python -m venv .venv && source .venv/bin/activate
|
|
72
|
+
pip install -r requirements.txt
|
|
73
|
+
pip install -e .
|
|
74
|
+
|
|
75
|
+
# Run one dataset end-to-end
|
|
76
|
+
python scripts/train.py --dataset emotions --results_dir results/run-dev
|
|
77
|
+
python scripts/evaluate.py --dataset emotions --results_dir results/run-dev
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
To reproduce **every** number and figure in the paper, see
|
|
81
|
+
[REPRODUCE.md](REPRODUCE.md) — it covers the full pipeline, expected wall
|
|
82
|
+
times, and the exact environment.
|
|
83
|
+
|
|
84
|
+
## Datasets
|
|
85
|
+
|
|
86
|
+
Ten multi-label datasets are used:
|
|
87
|
+
`chd_49`, `emotions`, `scene`, `yeast`, `water_quality`, `humanpseaac`,
|
|
88
|
+
`gpositivepseaac`, `plantpseaac`, `viruspseaac`, and `enron`.
|
|
89
|
+
|
|
90
|
+
The first nine ARFFs are bundled under `data/`, so the pipeline runs
|
|
91
|
+
end-to-end right after `pip install`. `enron.arff` (K=53) is downloaded
|
|
92
|
+
separately — see [REPRODUCE.md §2](REPRODUCE.md). CLI keys match
|
|
93
|
+
`preorder4mlc.config::ConfigManager.DATASET_CONFIGS`.
|
|
94
|
+
|
|
95
|
+
## Partial abstention
|
|
96
|
+
|
|
97
|
+
A partial-abstention prediction is a vector in `{0, 1, −1}` where `−1`
|
|
98
|
+
means **"abstain"** on that label. This lets the model stay silent where
|
|
99
|
+
it is uncertain instead of forcing a 0/1 call. Two pairs of metrics
|
|
100
|
+
capture the trade-off — *recovery* (did the abstentions cover the truth?)
|
|
101
|
+
and *abstention rate* (how often did it abstain?):
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
ŷ = [1, 0, 1, −1, 0, −1] y = [0, 0, 1, 1, 0, 0]
|
|
105
|
+
|
|
106
|
+
AREC = (0 + 1 + 1 + 1 + 1 + 1) / 6 = 4/6 # −1 counts as covering {0,1}
|
|
107
|
+
AABS = 2 / 6 # fraction abstained
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Full definitions (`AREC`, `AABS`, `REC`, `ABS`) live in
|
|
111
|
+
`preorder4mlc.evaluation_metric`.
|
|
112
|
+
|
|
113
|
+
## Repository layout
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
preorder4mlc/ # Library package
|
|
117
|
+
├── config.py # Run configuration + dataset registry
|
|
118
|
+
├── datasets4experiments.py # ARFF loading, k-fold splits, label noise
|
|
119
|
+
├── base_classifiers.py # Pairwise / calibrated classifier factory
|
|
120
|
+
├── estimator.py # Uniform interface over RF / ETC / XGBoost / LightGBM
|
|
121
|
+
├── inference_models.py # PredictBOPOs (BOPOs + BR / CC / CLR baselines)
|
|
122
|
+
├── searching_algorithms.py # ILP search for pre- and partial-orders
|
|
123
|
+
├── training_orchestrator.py # Training loop over learners × folds × algorithms
|
|
124
|
+
├── evaluation_metric.py # Example-, label-, ranking-, abstention-metrics
|
|
125
|
+
└── utils/ # Summaries, statistical tests, figures
|
|
126
|
+
|
|
127
|
+
scripts/ # CLI entry points
|
|
128
|
+
├── train.py / evaluate.py # BOPOs + CLR / BR / CC
|
|
129
|
+
├── train_ecc.py / evaluate_ecc.py # ECC baseline
|
|
130
|
+
└── smoke_predict_bopos.py # Behavior-preservation smoke test
|
|
131
|
+
|
|
132
|
+
data/ # 9 bundled ARFFs (enron downloaded separately)
|
|
133
|
+
results/ # Per-fold CSVs + aggregated tables
|
|
134
|
+
run.sh # End-to-end reproduction driver
|
|
135
|
+
REPRODUCE.md # Step-by-step reproduction recipe
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Citation
|
|
139
|
+
|
|
140
|
+
If you use this code, please cite the paper (see
|
|
141
|
+
[CITATION.cff](CITATION.cff)):
|
|
142
|
+
|
|
143
|
+
```bibtex
|
|
144
|
+
@article{nguyen2026robust,
|
|
145
|
+
title = {Robust Multi-Label Classification via Preference Learning},
|
|
146
|
+
author = {Nguyen, Vu-Linh and Hoang, Xuan-Truong and Destercke, S{\'e}bastien and de Campos, Cassio and Huynh, Van-Nam},
|
|
147
|
+
journal = {Machine Learning},
|
|
148
|
+
publisher = {Springer},
|
|
149
|
+
year = {2026},
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
Released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Reproducing the paper results
|
|
2
|
+
|
|
3
|
+
This document records the exact steps required to reproduce every number
|
|
4
|
+
and figure reported in the journal-revision paper from a clean clone of
|
|
5
|
+
this repository.
|
|
6
|
+
|
|
7
|
+
## 1. Environment
|
|
8
|
+
|
|
9
|
+
Tested on Python 3.12 with the pinned versions in `requirements.txt`.
|
|
10
|
+
GLPK headers must be present on the system so that `cvxopt.glpk` can
|
|
11
|
+
solve the per-instance ILP.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Ubuntu / Debian
|
|
15
|
+
sudo apt-get install libglpk-dev
|
|
16
|
+
|
|
17
|
+
# Python deps
|
|
18
|
+
python -m venv .venv
|
|
19
|
+
source .venv/bin/activate
|
|
20
|
+
pip install -r requirements.txt
|
|
21
|
+
pip install -e .
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 2. Data
|
|
25
|
+
|
|
26
|
+
Ten multi-label datasets are used in the paper. Nine ARFFs are tracked
|
|
27
|
+
under `data/` for one-click reproduction; `enron.arff` (K=53) must be
|
|
28
|
+
downloaded separately from COMETA / MULAN and placed at
|
|
29
|
+
`data/enron.arff`.
|
|
30
|
+
|
|
31
|
+
| Key (CLI) | File | Labels | Source |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `chd_49` | `CHD_49.arff` | 6 | Coronary heart disease |
|
|
34
|
+
| `emotions` | `emotions.arff` | 6 | Mulan repository |
|
|
35
|
+
| `scene` | `scene.arff` | 6 | Mulan repository |
|
|
36
|
+
| `yeast` | `Yeast.arff` | 14 | Mulan repository |
|
|
37
|
+
| `water_quality` | `Water-quality.arff` | 14 | UCI |
|
|
38
|
+
| `humanpseaac` | `HumanPseAAC.arff` | 14 | Pse-AAC encoding |
|
|
39
|
+
| `gpositivepseaac` | `GpositivePseAAC.arff` | 4 | Pse-AAC encoding |
|
|
40
|
+
| `plantpseaac` | `PlantPseAAC.arff` | 12 | Pse-AAC encoding |
|
|
41
|
+
| `viruspseaac` | `VirusPseAAC.arff` | 6 | Pse-AAC encoding |
|
|
42
|
+
| `enron` | `enron.arff` | 53 | COMETA / MULAN (not bundled) |
|
|
43
|
+
|
|
44
|
+
## 3. Determinism
|
|
45
|
+
|
|
46
|
+
All splits, folds, and label-noise draws are seeded by
|
|
47
|
+
`preorder4mlc.constants.RANDOM_STATE = 6`. The per-fold parallel
|
|
48
|
+
training step uses `joblib.Parallel(n_jobs=-1)`; sklearn ensemble
|
|
49
|
+
estimators are seeded through `RANDOM_STATE` as well so identical
|
|
50
|
+
splits produce identical predictions.
|
|
51
|
+
|
|
52
|
+
## 4. Reproducing all results
|
|
53
|
+
|
|
54
|
+
The repository ships **two drivers** for the same pipeline. Both call the
|
|
55
|
+
same four `scripts/*.py` entry points per dataset; they differ only in how
|
|
56
|
+
the work is orchestrated. Pick one:
|
|
57
|
+
|
|
58
|
+
| | `run.sh` | `scripts/slurm/submit_all.sh` |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| Target | a single machine | a SLURM HPC cluster |
|
|
61
|
+
| Execution | datasets run sequentially | hundreds of array tasks in parallel |
|
|
62
|
+
| Resume | re-runs everything from scratch | skips cells already complete on disk |
|
|
63
|
+
| Best for | small/quick runs, a few datasets | full reproduction incl. `enron` (K=53) |
|
|
64
|
+
|
|
65
|
+
Whichever driver you use, each dataset runs the same four steps in order:
|
|
66
|
+
|
|
67
|
+
1. `python scripts/train.py --dataset <key> --results_dir <dir>` —
|
|
68
|
+
train pairwise classifiers, BOPOs (pre- and partial-order), and the
|
|
69
|
+
CLR / BR / CC baselines.
|
|
70
|
+
2. `python scripts/evaluate.py --dataset <key> --results_dir <dir>` —
|
|
71
|
+
write per-fold evaluation CSVs for the BOPOs / CLR / BR / CC pickles.
|
|
72
|
+
3. `python scripts/train_ecc.py --dataset <key> --algorithm ecc
|
|
73
|
+
--results_dir <dir>` — train the ECC (Ensemble of Classifier Chains)
|
|
74
|
+
baseline.
|
|
75
|
+
4. `python scripts/evaluate_ecc.py --dataset <key> --algorithm ecc
|
|
76
|
+
--results_dir <dir>` — write per-fold evaluation CSVs for ECC.
|
|
77
|
+
|
|
78
|
+
### 4a. Single machine — `run.sh`
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
RESULTS_DIR=results/run-$(date +%Y%m%d) bash run.sh
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Runs all ten datasets sequentially with the default base learner (Random
|
|
85
|
+
Forest). Per-dataset stdout/stderr lands in `logs/run-<date>/<dataset>.log`.
|
|
86
|
+
To reproduce the LightGBM variant, pass `--base_learner lgbm` to both
|
|
87
|
+
`train.py` and `train_ecc.py`.
|
|
88
|
+
|
|
89
|
+
`run.sh` does **not** skip completed work and has no `enron` throttle, so it
|
|
90
|
+
suits local runs of the lighter datasets. For the full matrix — especially
|
|
91
|
+
`enron`, which needs an HPC node and the HiGHS solver (see §7) — use the
|
|
92
|
+
SLURM driver below.
|
|
93
|
+
|
|
94
|
+
### 4b. HPC cluster — `scripts/slurm/submit_all.sh`
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Submit the full RF + LightGBM matrix; results land in
|
|
98
|
+
# results/rerun_<date>_rf and results/rerun_<date>_lgbm by default.
|
|
99
|
+
bash scripts/slurm/submit_all.sh
|
|
100
|
+
|
|
101
|
+
# Preview the sbatch plan without submitting:
|
|
102
|
+
bash scripts/slurm/submit_all.sh --dry-run
|
|
103
|
+
|
|
104
|
+
# Restrict learners / datasets via env vars:
|
|
105
|
+
LEARNERS="RF" bash scripts/slurm/submit_all.sh # RF only
|
|
106
|
+
DATASETS="viruspseaac" bash scripts/slurm/submit_all.sh # one dataset
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The controller expands the full matrix (10 datasets × 4 noise levels × 5
|
|
110
|
+
algorithms × {RF, LightGBM}) into array jobs, **skips any cell already
|
|
111
|
+
complete on disk**, and submits eval jobs with
|
|
112
|
+
`--dependency=afterok:<train-jobids>`. It respects the cluster QOS submit
|
|
113
|
+
cap (`SUBMIT_CAP`) with backoff, and throttles the heavy `enron` BOPOS
|
|
114
|
+
arrays (`ENRON_QUEUE_FRACTION`, default 0.4) so other datasets keep ~60% of
|
|
115
|
+
the queue; the throttle lifts automatically once every non-`enron` cell is
|
|
116
|
+
done. Logs land in `slurm_logs/`; watch with `squeue -u $USER`.
|
|
117
|
+
|
|
118
|
+
`merge_split_results.py` reassembles the per-repeat sub-arrays that the
|
|
119
|
+
`enron` throttle splits jobs into. After all eval jobs finish, aggregate
|
|
120
|
+
with `summarize_metrics` (§5).
|
|
121
|
+
|
|
122
|
+
## 5. Summarising into the paper tables
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
python -m preorder4mlc.utils.summarize_metrics \
|
|
126
|
+
--results_dir results/run-<date> \
|
|
127
|
+
--output_dir results/run-<date>_summary
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Writes one `<Dataset>_<PredictionType>_summary.csv` per dataset to the
|
|
131
|
+
output directory. `PredictionType` is one of `BinaryVector`,
|
|
132
|
+
`PartialAbstention`, or `ScoreVector`.
|
|
133
|
+
|
|
134
|
+
## 6. Statistical tests and figures
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
python -m preorder4mlc.utils.statistical_tests \
|
|
138
|
+
--results_dir results/run-<date>_summary \
|
|
139
|
+
--output_dir results/run-<date>_summary/stats
|
|
140
|
+
|
|
141
|
+
python -m preorder4mlc.utils.plot_figures \
|
|
142
|
+
--results_dir results/run-<date>_summary \
|
|
143
|
+
--raw_results_dir results/run-<date>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The figure script writes critical-difference diagrams, average-rank vs
|
|
147
|
+
noise curves, abstention plots, Hamming/Subset trade-offs, and rank
|
|
148
|
+
heatmaps to `results/run-<date>_summary/figures/`.
|
|
149
|
+
|
|
150
|
+
## 7. Compute budget
|
|
151
|
+
|
|
152
|
+
Single-machine wall time (5 repeats x 5 folds, joblib across all CPUs),
|
|
153
|
+
per dataset, with Random Forest as the base learner:
|
|
154
|
+
|
|
155
|
+
| Dataset | Wall time |
|
|
156
|
+
|---|---|
|
|
157
|
+
| chd_49 | ~4 min |
|
|
158
|
+
| gpositivepseaac | ~5 min |
|
|
159
|
+
| viruspseaac | ~5 min |
|
|
160
|
+
| emotions | ~6 min |
|
|
161
|
+
| plantpseaac | ~30 min |
|
|
162
|
+
| scene | ~40 min |
|
|
163
|
+
| water_quality | ~60 min |
|
|
164
|
+
| yeast | ~60 min |
|
|
165
|
+
| humanpseaac | ~2.5 h |
|
|
166
|
+
| enron | per-fold ~18 min on an HPC node (K=53; uses the HiGHS solver — set `PREORDER_SOLVER=highs` — and ~300 GB RAM; GLPK is intractable at this label count) |
|
|
167
|
+
|
|
168
|
+
ECC adds at most ~30 min per dataset (typically far less). For HPC
|
|
169
|
+
re-runs, dataset jobs can be submitted in parallel.
|
|
170
|
+
|
|
171
|
+
## 8. Output bundle
|
|
172
|
+
|
|
173
|
+
After step 5 the run directory contains:
|
|
174
|
+
|
|
175
|
+
* `results/run-<date>/*.pkl` — per-fold training records (not tracked
|
|
176
|
+
by git; recreated by step 1).
|
|
177
|
+
* `results/run-<date>/evaluation_*.csv` — per-fold metric CSVs.
|
|
178
|
+
* `results/run-<date>_summary/*_summary.csv` — per-dataset aggregate
|
|
179
|
+
tables (one per `<Dataset>_<PredictionType>`).
|
|
180
|
+
|
|
181
|
+
The canonical aggregate tables that produced the paper numbers ship as
|
|
182
|
+
CSV under:
|
|
183
|
+
|
|
184
|
+
* `results/final_rf_summary/` — Random Forest (paper default).
|
|
185
|
+
* `results/final_lgbm_summary/` — LightGBM variant.
|
|
186
|
+
|
|
187
|
+
Each also keeps its raw `results/final_rf/` and `results/final_lgbm/`
|
|
188
|
+
per-fold pickles + `evaluation_*.csv` on disk (pickles untracked) so the
|
|
189
|
+
summaries can be re-aggregated via step 5 without retraining. New runs
|
|
190
|
+
can be diffed against these CSVs to confirm equivalence. The optional
|
|
191
|
+
statistical tests and figures (step 6) are not shipped; regenerate them
|
|
192
|
+
from the summary CSVs as needed.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Conventions
|
|
2
|
+
|
|
3
|
+
- **Package layout:** flat `preorder4mlc/` package; CLIs live in `scripts/`.
|
|
4
|
+
- **Datasets:** registered in `preorder4mlc/config.py` (`ConfigManager.DATASET_CONFIGS`);
|
|
5
|
+
loaded by `preorder4mlc/datasets4experiments.py`.
|
|
6
|
+
- **Results:** per-fold CSVs under `results/<run>/`; aggregated by
|
|
7
|
+
`preorder4mlc/utils/summarize_metrics.py`.
|
|
8
|
+
- **Solvers:** ILP search uses HiGHS (`highspy`) with a CVXOPT fallback (`solvers.py`).
|
|
9
|
+
- **Versioning:** keep `pyproject.toml`, `.zenodo.json`, `CITATION.cff` in lockstep.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Extending preorder4mlc
|
|
2
|
+
|
|
3
|
+
## Add a dataset
|
|
4
|
+
Register it in `preorder4mlc/config.py` (`ConfigManager.DATASET_CONFIGS`) with its label
|
|
5
|
+
count and file orientation, and ensure `preorder4mlc/datasets4experiments.py` can load its
|
|
6
|
+
ARFF/CSV. Then add its key to the `DATASETS` array in `run.sh`.
|
|
7
|
+
|
|
8
|
+
## Add a base classifier
|
|
9
|
+
Implement it in `preorder4mlc/base_classifiers.py` following the existing pairwise /
|
|
10
|
+
label-ranking interface (must expose `fit` / `predict`-style methods consumed by
|
|
11
|
+
`training_orchestrator.py`).
|
|
12
|
+
|
|
13
|
+
## Add an evaluation metric
|
|
14
|
+
Add the metric to `preorder4mlc/evaluation_metric.py`; it is then available to the
|
|
15
|
+
evaluation scripts and the summary tables.
|
|
16
|
+
|
|
17
|
+
## Change the ILP search
|
|
18
|
+
The search objective and constraints live in `preorder4mlc/searching_algorithms.py` and
|
|
19
|
+
`preorder4mlc/solvers.py` (HiGHS via `highspy`, CVXOPT fallback).
|