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.
Files changed (37) hide show
  1. preorder4mlc-1.0.0/CITATION.cff +57 -0
  2. preorder4mlc-1.0.0/LICENSE +21 -0
  3. preorder4mlc-1.0.0/MANIFEST.in +8 -0
  4. preorder4mlc-1.0.0/PKG-INFO +213 -0
  5. preorder4mlc-1.0.0/README.md +155 -0
  6. preorder4mlc-1.0.0/REPRODUCE.md +192 -0
  7. preorder4mlc-1.0.0/docs/CONVENTIONS.md +9 -0
  8. preorder4mlc-1.0.0/docs/EXTENDING.md +19 -0
  9. preorder4mlc-1.0.0/docs/RELEASE_CHECKLIST.md +24 -0
  10. preorder4mlc-1.0.0/docs/REPRODUCING.md +31 -0
  11. preorder4mlc-1.0.0/docs/paper.yaml +30 -0
  12. preorder4mlc-1.0.0/preorder4mlc/__init__.py +4 -0
  13. preorder4mlc-1.0.0/preorder4mlc/base_classifiers.py +242 -0
  14. preorder4mlc-1.0.0/preorder4mlc/config.py +115 -0
  15. preorder4mlc-1.0.0/preorder4mlc/constants.py +30 -0
  16. preorder4mlc-1.0.0/preorder4mlc/datasets4experiments.py +176 -0
  17. preorder4mlc-1.0.0/preorder4mlc/estimator.py +123 -0
  18. preorder4mlc-1.0.0/preorder4mlc/evaluation_metric.py +888 -0
  19. preorder4mlc-1.0.0/preorder4mlc/inference_models.py +502 -0
  20. preorder4mlc-1.0.0/preorder4mlc/searching_algorithms.py +517 -0
  21. preorder4mlc-1.0.0/preorder4mlc/solvers.py +178 -0
  22. preorder4mlc-1.0.0/preorder4mlc/training_orchestrator.py +474 -0
  23. preorder4mlc-1.0.0/preorder4mlc/utils/plot_figures.py +1014 -0
  24. preorder4mlc-1.0.0/preorder4mlc/utils/results_manager.py +167 -0
  25. preorder4mlc-1.0.0/preorder4mlc/utils/statistical_tests.py +411 -0
  26. preorder4mlc-1.0.0/preorder4mlc/utils/summarize_metrics.py +250 -0
  27. preorder4mlc-1.0.0/preorder4mlc/utils/suppress.py +55 -0
  28. preorder4mlc-1.0.0/preorder4mlc.egg-info/PKG-INFO +213 -0
  29. preorder4mlc-1.0.0/preorder4mlc.egg-info/SOURCES.txt +35 -0
  30. preorder4mlc-1.0.0/preorder4mlc.egg-info/dependency_links.txt +1 -0
  31. preorder4mlc-1.0.0/preorder4mlc.egg-info/requires.txt +22 -0
  32. preorder4mlc-1.0.0/preorder4mlc.egg-info/top_level.txt +1 -0
  33. preorder4mlc-1.0.0/pyproject.toml +101 -0
  34. preorder4mlc-1.0.0/requirements-core.txt +10 -0
  35. preorder4mlc-1.0.0/requirements.txt +13 -0
  36. preorder4mlc-1.0.0/setup.cfg +4 -0
  37. 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,8 @@
1
+ include LICENSE
2
+ include README.md
3
+ include REPRODUCE.md
4
+ include CITATION.cff
5
+ include requirements.txt
6
+ include requirements-core.txt
7
+ recursive-include docs *.md *.yaml
8
+ prune docs/superpowers
@@ -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: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
62
+ [![Python](https://img.shields.io/badge/python-3.12-blue)](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: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
4
+ [![Python](https://img.shields.io/badge/python-3.12-blue)](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).