schaeferbasti commited on
Commit
f77b3a8
·
verified ·
1 Parent(s): 75388fa

Upload 5 files

Browse files
Files changed (5) hide show
  1. AGENTS.md +45 -0
  2. CLAUDE.md +10 -0
  3. README.md +47 -6
  4. index.html +170 -17
  5. ruff.toml +2 -0
AGENTS.md ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AGENTS.md
2
+
3
+ The SelectArena leaderboard: a static Hugging Face Space (`sdk: static`) that serves files
4
+ generated in the [SelectArena](https://github.com/schaeferbasti/SelectArena) repo. Static Spaces
5
+ run no compute, so they are free; do not switch it to Gradio or Docker (those need a paid plan).
6
+
7
+ ## Files
8
+
9
+ - `index.html`: the whole page: header, the four tab panels (Leaderboard, Per dataset,
10
+ Stability & validity, About), all user-facing text, the citation, `<meta name="selectarena-version">`
11
+ and the version history (`<ul id="version-history">`, newest first).
12
+ - `assets/app.js`: plain JavaScript, no build step. Fetches `data/meta.json`, renders the selector
13
+ chips (task type, downstream model, budget; combinations that are not published are disabled),
14
+ sets the iframes' `src` to the generated pages and resizes them when a page posts
15
+ `{saFrameHeight}`. Keeps the selection in the URL hash.
16
+ - `assets/style.css`: color tokens on `:root` (light) and in `prefers-color-scheme: dark`.
17
+ - `smoke_test.py`: standard-library check of `data/` and of the version (see below).
18
+
19
+ ## Data contract
20
+
21
+ `data/` is SelectArena's `generated_website_artifacts/clean_website_artifacts/website_data/`:
22
+
23
+ - `meta.json`: counts, `models` (key -> name), `budgets`, `total_budget`, `task_types`,
24
+ `has_stability`, `has_validity`, `validity_noise`, `generated_at`, and `subsets` (each with
25
+ `tasks`, `model`, `budget`, `path`, `n_methods`, `n_datasets`, `n_comparisons`).
26
+ - `subsets/tasks_<t>/models_<m>/budgets_<b>/`: `website_leaderboard.csv`, `leaderboard_table.html`,
27
+ `elo_explorer.html`.
28
+ - `per_dataset.csv`, `per_dataset_table.html`, and optionally `stability.csv`,
29
+ `stability_table.html`, `validity.csv`, `validity_table.html`.
30
+
31
+ The generated pages are self-contained (inline CSS/JS, no network) and post their height to the
32
+ parent window. `subsetDir()` in `app.js` mirrors `selectarena.website.subsets.Subset.rel_path`;
33
+ change both together.
34
+
35
+ ## Conventions
36
+
37
+ - Never hand-edit `data/`: refresh it with the `update-leaderboard` skill in the SelectArena repo
38
+ (`../SelectArena/.claude/skills/update-leaderboard/`), which deletes the old content before copying.
39
+ - Every refresh bumps `selectarena-version` in `index.html` (patch for a data refresh, minor for
40
+ site changes) and adds a matching entry at the top of the version history
41
+ (`<li><strong>YYYY/MM/DD · vX.Y.Z</strong>: ...</li>`). `smoke_test.py` fails if they differ.
42
+ - No external scripts, fonts or CDNs; everything is served from this repo.
43
+ - Verification: `python smoke_test.py`, then `python -m http.server 8000` and a look at
44
+ http://localhost:8000 (all four tabs, a few selections, light and dark mode).
45
+ - Do not commit or push without an explicit request: pushing deploys the Space.
CLAUDE.md ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # CLAUDE.md
2
+
3
+ Read `AGENTS.md`: it is the guide for this repo (files, the `data/` contract, conventions).
4
+
5
+ - Static Space: `index.html` (page, text, version history), `assets/app.js`, `assets/style.css`.
6
+ Keep it static; Gradio or Docker Spaces need a paid plan.
7
+ - `data/` is generated in the SelectArena repo; never edit it by hand. To refresh it, use the
8
+ `update-leaderboard` skill from `../SelectArena/.claude/skills/` and pass it this repo's path.
9
+ - Check changes with `python smoke_test.py` and `python -m http.server 8000` (http://localhost:8000).
10
+ - Do not commit or push unless asked: pushing deploys the Space.
README.md CHANGED
@@ -1,10 +1,51 @@
1
  ---
2
- title: Leaderboard
3
- emoji: 👀
4
- colorFrom: pink
5
- colorTo: indigo
6
  sdk: static
7
- pinned: false
 
 
 
 
 
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: SelectArena Leaderboard
3
+ emoji: 🏅
4
+ colorFrom: blue
5
+ colorTo: yellow
6
  sdk: static
7
+ app_file: index.html
8
+ pinned: true
9
+ license: apache-2.0
10
+ short_description: Leaderboard of feature selection methods on tabular data
11
+ tags:
12
+ - leaderboard
13
+ - feature-selection
14
+ - tabular
15
  ---
16
 
17
+ # SelectArena Leaderboard
18
+
19
+ The leaderboard of [SelectArena](https://github.com/schaeferbasti/SelectArena)
20
+ ([paper](https://arxiv.org/abs/2610.13644)). It is a **static** Space: plain HTML, CSS and
21
+ JavaScript served as files, so it needs no compute and no paid plan. As for the
22
+ [TabArena leaderboard](https://huggingface.co/spaces/TabArena/leaderboard), this repo holds the site
23
+ and the data in `data/` is generated in the SelectArena repo.
24
+
25
+ ## Files
26
+
27
+ - `index.html`: the page, all its text, the current version and the version history.
28
+ - `assets/app.js`: reads `data/meta.json`, builds the selectors and embeds the generated pages.
29
+ - `assets/style.css`: layout and light / dark colors.
30
+ - `data/`: generated by SelectArena's `scripts/run_generate_website_artifacts.py`; never edit by hand.
31
+ - `smoke_test.py`: checks `data/` and the version (standard library only).
32
+
33
+ ## Preview
34
+
35
+ ```bash
36
+ python smoke_test.py
37
+ python -m http.server 8000 # then open http://localhost:8000
38
+ ```
39
+
40
+ Opening `index.html` directly from disk does not work: browsers block `fetch()` of local files.
41
+
42
+ ## Updating the results
43
+
44
+ Use the `update-leaderboard` skill of the SelectArena repo (`.claude/skills/update-leaderboard/`)
45
+ with this checkout's path. By hand:
46
+
47
+ 1. In SelectArena: `python scripts/run_generate_website_artifacts.py`.
48
+ 2. Here: delete the content of `data/`, then copy in the content of SelectArena's
49
+ `generated_website_artifacts/clean_website_artifacts/website_data/`.
50
+ 3. In `index.html`, bump `selectarena-version` and add an entry at the top of the version history.
51
+ 4. `python smoke_test.py`, preview, then `git add -A && git commit && git push` (pushing deploys).
index.html CHANGED
@@ -1,19 +1,172 @@
1
  <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
  <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <!-- Bumped with every data refresh, together with the version history at the bottom. -->
7
+ <meta name="selectarena-version" content="0.1.0">
8
+ <title>SelectArena Leaderboard</title>
9
+ <meta name="description" content="Leaderboard of feature selection methods on real-world tabular data.">
10
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='1' y='7' width='4' height='8' fill='%230072B2'/%3E%3Crect x='6' y='3' width='4' height='12' fill='%23D55E00'/%3E%3Crect x='11' y='5' width='4' height='10' fill='%230072B2'/%3E%3C/svg%3E">
11
+ <link rel="stylesheet" href="assets/style.css">
12
+ </head>
13
+ <body>
14
+ <div class="page">
15
+ <header class="header">
16
+ <h1><span class="mark">Select</span>Arena</h1>
17
+ <p class="subtitle">A living benchmark for feature selection on real-world tabular data</p>
18
+ <ul class="facts" id="facts"></ul>
19
+ <nav class="links">
20
+ <a href="https://arxiv.org/abs/2610.13644" target="_blank" rel="noopener">Paper</a>
21
+ <a href="https://github.com/schaeferbasti/SelectArena" target="_blank" rel="noopener">Code</a>
22
+ <a href="https://github.com/autogluon/tabarena" target="_blank" rel="noopener">Built on TabArena</a>
23
+ </nav>
24
+ </header>
25
+
26
+ <p class="intro">
27
+ Each feature selection method keeps a fixed budget of a dataset's features; a downstream model is
28
+ then trained on the selected features only. Methods compete on the same dataset split, downstream
29
+ model and budget, and the leaderboard ranks them by <strong>Elo</strong>. Pick a task type,
30
+ downstream model or budget to see the leaderboard of that slice.
31
+ </p>
32
+
33
+ <div class="tabs" role="tablist" aria-label="Leaderboard sections">
34
+ <button role="tab" id="tab-leaderboard" aria-controls="panel-leaderboard" aria-selected="true" data-tab="leaderboard">Leaderboard</button>
35
+ <button role="tab" id="tab-datasets" aria-controls="panel-datasets" aria-selected="false" data-tab="datasets">Per dataset</button>
36
+ <button role="tab" id="tab-robustness" aria-controls="panel-robustness" aria-selected="false" data-tab="robustness">Stability &amp; validity</button>
37
+ <button role="tab" id="tab-about" aria-controls="panel-about" aria-selected="false" data-tab="about">About</button>
38
+ </div>
39
+
40
+ <!-- Leaderboard -->
41
+ <section role="tabpanel" id="panel-leaderboard" aria-labelledby="tab-leaderboard">
42
+ <div id="no-results" class="notice" hidden>
43
+ <strong>No results published yet.</strong> The leaderboard fills in once the first benchmark
44
+ results are published from the
45
+ <a href="https://github.com/schaeferbasti/SelectArena" target="_blank" rel="noopener">SelectArena repository</a>.
46
+ </div>
47
+ <div id="leaderboard-content" hidden>
48
+ <div class="controls">
49
+ <div class="control"><span class="control-label" id="label-tasks">Task type</span>
50
+ <div class="chips" id="chips-tasks" role="group" aria-labelledby="label-tasks"></div></div>
51
+ <div class="control"><span class="control-label" id="label-model">Downstream model</span>
52
+ <div class="chips" id="chips-model" role="group" aria-labelledby="label-model"></div></div>
53
+ <div class="control"><span class="control-label" id="label-budget">Feature budget</span>
54
+ <div class="chips" id="chips-budget" role="group" aria-labelledby="label-budget"></div></div>
55
+ </div>
56
+ <p class="summary" id="summary" aria-live="polite"></p>
57
+ <div id="subset-missing" class="notice" hidden>
58
+ No leaderboard for this selection: fewer than two methods have results.
59
+ </div>
60
+ <div id="subset-content">
61
+ <iframe class="frame sa-frame" id="frame-figure" title="Elo rating with stability and validity" style="height:480px"></iframe>
62
+ <p class="caption">
63
+ <strong>Elo rating of each feature selection method, from worst to best.</strong> Elo
64
+ summarizes how often a method beats another on the same dataset, budget and downstream model
65
+ (lower downstream error wins), with Random anchored at 1000 (dashed line). Error bars are 95%
66
+ intervals from cluster-bootstrap resamples of the datasets. The left bar of each method is
67
+ shaded by <span class="stab">stability</span> (how little the selected subset changes across
68
+ bootstrap resamples of the data), the right bar by <span class="val">validity</span> (how well
69
+ injected noise features are rejected); darker is better for both. Hatched bars have no
70
+ stability or validity result yet.
71
+ </p>
72
+ <iframe class="frame sa-frame" id="frame-table" title="Leaderboard table" style="height:640px"></iframe>
73
+ </div>
74
+ </div>
75
+ </section>
76
+
77
+ <!-- Per dataset -->
78
+ <section role="tabpanel" id="panel-datasets" aria-labelledby="tab-datasets" hidden>
79
+ <p class="prose">Mean rank of each method on each dataset, over splits, downstream models and budgets (1 is best).</p>
80
+ <div id="datasets-missing" class="notice" hidden>No per-dataset results published yet.</div>
81
+ <iframe class="frame sa-frame" id="frame-datasets" title="Mean rank per dataset" style="height:900px"></iframe>
82
+ </section>
83
+
84
+ <!-- Stability & validity -->
85
+ <section role="tabpanel" id="panel-robustness" aria-labelledby="tab-robustness" hidden>
86
+ <div class="prose">
87
+ <p>These metrics come from runs of the selectors alone, without a downstream model.</p>
88
+ <ul>
89
+ <li><strong>Stability</strong> (Nogueira, Sechidis &amp; Brown, JMLR 2018): agreement of the
90
+ selected features across bootstrap resamples of the data, corrected for chance; 1 means
91
+ identical selections, 0 the agreement of random selections.</li>
92
+ <li><strong>Validity</strong>: share of the budget filled with original features after synthetic
93
+ noise features are added (the noise level is the number of noise features per original one).
94
+ The leaderboard and the figure use the validity at noise level <span id="validity-noise">1.0</span>.</li>
95
+ </ul>
96
+ </div>
97
+ <h2>Stability</h2>
98
+ <div id="stability-missing" class="notice" hidden>No stability results published yet.</div>
99
+ <iframe class="frame sa-frame" id="frame-stability" title="Stability per method" style="height:640px"></iframe>
100
+ <h2>Validity</h2>
101
+ <div id="validity-missing" class="notice" hidden>No validity results published yet.</div>
102
+ <iframe class="frame sa-frame" id="frame-validity" title="Validity per method" style="height:900px"></iframe>
103
+ </section>
104
+
105
+ <!-- About -->
106
+ <section role="tabpanel" id="panel-about" aria-labelledby="tab-about" hidden>
107
+ <div class="prose">
108
+ <h2>How the leaderboard is computed</h2>
109
+ <p>Methods are compared within a <em>comparison group</em>: one dataset split, one downstream
110
+ model configuration and one feature budget.</p>
111
+ <ul>
112
+ <li><strong>Elo</strong>: Bradley-Terry rating fit on all pairwise matches. Within each dataset,
113
+ every combination of budget and downstream model (errors averaged over splits) is a setting in
114
+ which every pair of methods plays a match, won by the lower error; ties are skipped. Random is
115
+ anchored at 1000; a gap of 150 points means about 70% win probability. The 95% interval comes
116
+ from cluster-bootstrap resamples of the datasets.</li>
117
+ <li><strong>Avg. rank</strong>: mean rank of the method's downstream error within the groups (1 is best).</li>
118
+ <li><strong>Win rate</strong>: share of pairwise comparisons won against the other methods (ties count half).</li>
119
+ <li><strong>Improvability</strong>: mean relative gap <code>(error − best error) / error</code> to
120
+ the best method of the group (0 is best).</li>
121
+ <li><strong>Error vs. all features</strong>: mean ratio of the error to the same model trained on
122
+ all features. Below 1 means the selection improved the model.</li>
123
+ <li><strong>Stability</strong> and <strong>Validity</strong>: see the <em>Stability &amp; validity</em> tab.</li>
124
+ <li><strong>Time</strong>: median wall-clock time of the selection. <strong>Fallback</strong>:
125
+ share of runs in which the method ran out of time and random features filled the budget.</li>
126
+ </ul>
127
+ <p><strong>Budgets.</strong> Budget <em>i</em> of <em>b</em> keeps <code>ceil(d · i / (b + 1))</code>
128
+ of the <code>d</code> features when <code>d ≤ 100</code>, and <code>ceil(d ^ (i / (b + 1)))</code> otherwise.</p>
129
+ <p><strong>Method types.</strong> <em>Filter</em> methods score features from the data alone,
130
+ <em>wrapper</em> methods search feature subsets by refitting a proxy model, <em>embedded</em>
131
+ methods read the selection off a fitted model. Random is the baseline.</p>
132
+
133
+ <h2>Adding a method</h2>
134
+ <p>Implement the method as described in the
135
+ <a href="https://github.com/schaeferbasti/SelectArena" target="_blank" rel="noopener">SelectArena repository</a>
136
+ (one <code>AbstractFeatureSelector</code> subclass) and open a pull request or an issue there.</p>
137
+
138
+ <h2>Data</h2>
139
+ <p>Everything shown here is plain files in this Space's <code>data/</code> folder:
140
+ <a href="data/meta.json" target="_blank">meta.json</a> lists every published leaderboard, and each
141
+ one is a CSV, e.g. the
142
+ <a href="data/subsets/tasks_all/models_all/budgets_all/website_leaderboard.csv" target="_blank">overall leaderboard</a>.
143
+ Every table and figure also has its own CSV / SVG / PNG download button.</p>
144
+ </div>
145
+ </section>
146
+
147
+ <footer>
148
+ <details>
149
+ <summary>Citation</summary>
150
+ <pre>@article{schaefer2026selectarena,
151
+ title = {SelectArena: A Modern Benchmark for Feature Selection on Real-world Tabular Data},
152
+ author = {Sch{\"a}fer, Bastian and Matus, Dominika and Purucker, Lennart and Knauer, Ricardo and
153
+ Rodner, Erik and Hutter, Frank and Sokolov, Anton and Liefooghe, Arnaud},
154
+ journal = {arXiv preprint arXiv:2610.13644},
155
+ year = {2026}
156
+ }</pre>
157
+ </details>
158
+ <details>
159
+ <summary>Version history (current: <span id="current-version"></span>)</summary>
160
+ <!-- version-history: newest entry first; the top entry's version must equal selectarena-version above. -->
161
+ <ul class="history" id="version-history">
162
+ <li><strong>2026/10/13 · v0.1.0</strong>: Static leaderboard site (free Hugging Face static Space):
163
+ one leaderboard per task type, downstream model and budget, interactive main figure (Elo with
164
+ stability and validity), per-dataset ranks and stability / validity tables.</li>
165
+ </ul>
166
+ <!-- /version-history -->
167
+ </details>
168
+ </footer>
169
+ </div>
170
+ <script src="assets/app.js"></script>
171
+ </body>
172
  </html>
ruff.toml ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ line-length = 120
2
+ target-version = "py311"