louisldn commited on
Commit
a6828ea
·
1 Parent(s): 89c37e6

updated tabbench space with up-to-date data

Browse files
.DS_Store CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
 
app.py CHANGED
@@ -5,6 +5,11 @@ import pandas as pd
5
  import json
6
  import random
7
 
 
 
 
 
 
8
  # TabBench currently supports the following models, with new additions that keep coming:
9
  # - **NICL (Neuralk In-Context-Learning)**: Our in-house tabular foundation model based on an in-context learning architecture (proprietary).
10
  # - **TabICL**: A transformer-based model that performs feature compression before doing in-context learning on tabular data by conditioning on labeled support examples to predict unseen queries without task-specific training.
@@ -12,15 +17,13 @@ import random
12
  # - **XGBoost**: An optimized distributed gradient boosting library designed to be highly efficient, flexible, and portable.
13
  # - **CatBoost**: A gradient boosting on decision trees library, particularly strong with categorical features.
14
  # - **LightGBM**: A fast gradient boosting framework that builds decision trees using histogram-based learning for scalable, high-performance tabular modeling.
15
- # - **MLP**: A feedforward neural network that models tabular data by learning non-linear interactions between numerical and embedded categorical features.
16
- # - **Random Forest**: A robust ensemble method that builds multiple decision trees and averages their predictions to reduce overfitting and improve accuracy.
17
  # - **ModernNCA**: An advanced extension of Neighborhood Component Analysis (NCA) that employs deep neural networks with stochastic neighborhood sampling to learn complex feature interactions for tabular data.
18
  # - **RealMLP**: An enhanced MLP optimized with strong default parameters, achieving competitive performance on tabular data.
19
  # - **TabM**: A deep learning model that efficiently imitates an ensemble of MLPs, enhancing performance on tabular data tasks without the overhead of training multiple models.
20
  # It is capable of processing datasets up to 100× larger and running up to 10× faster than TabPFNv2.
21
 
22
  PUBLIC_DATASETS_TEXT = """
23
- We curate a list of **214 datasets** from OpenML that span various industries such as **retail, healthcare, finance, and more**.
24
 
25
  🔎 You can easily filter datasets by industry below or explore the industry specific leaderboards via the sidebar.
26
  """
@@ -28,8 +31,10 @@ We curate a list of **214 datasets** from OpenML that span various industries su
28
  MODELS_TEXT = """
29
  TabBench currently supports the following models, with more additions planned:
30
  - **Tabular foundation models**: NICL, TabICL, TabPFNv2
31
- - **Tree-based**: XGBoost, CatBoost, LightGBM, Random Forest
32
- - **Neural networks**: MLP, RealMLP, TabM, ModernNCA
 
 
33
  """
34
 
35
  BENCHMARKING_TEXT = """
@@ -47,32 +52,34 @@ Evaluation is optimized for ROC-AUC and preprocessing steps vary following each
47
  METRICS_TEXT = """
48
  TabBench uses different types of metrics to evaluate model performance:
49
  - **Classic metrics**: Accuracy, Precision, Recall, F1 score, AUC
50
- - **Ranking metrics**: Precision@k, Rank, Harmonic Rank, [Elo score?]
51
- - **Industry-relevant metrics**: [ADD WHICH]
52
  """
53
 
54
  TITLE = """
55
- <h1 style="text-align:center; color:#25ccb9;">
56
- TabBench
57
- </h1>
58
- <h2 style="text-align:center">
59
- An industry-first benchmark suite for machine learning on tabular data
60
- </h2>
 
 
 
61
  """
62
 
63
  INTRODUCTION_TEXT = """
64
- <p style="font-size: 16px; text-align:center">
65
  Bridging the gap between academic benchmarks and industry needs
66
  </p>
67
  """
68
 
69
  DATA_MAP_TEXT = """
70
- - 🔎 **Explore dataset statistics & distributions** by industry and data type (public vs proprietary)
71
- - 📈 **Compare public and proprietary datasets** to reveal how academic benchmarks might misrepresent model performance
72
  """
73
 
74
  PUBLIC_BENCHMARK_TEXT = """
75
- - 📊 **A curation of 200+ public datasets** across industries such as retail, healthcare, finance, energy, etc
76
  - 🤖 **Evaluations on 10+ powerful models** from gradient boosting and decision trees to tabular foundation models
77
  - 💥 **Integration of NICL**, the Neuralk AI tabular foundation model designed for industry-grade use cases
78
  - 🏅 **Leaderboards by sector** to discover which models perform best for each industry
@@ -87,7 +94,7 @@ PRIVATE_BENCHMARK_TEXT = """
87
  # rewrite new uses continuously being added
88
 
89
  PRIVATE_DATA_TEXT = """
90
- We curate a list of **60 proprietary datasets** from different retailers focused on the **use case of product categorization**.
91
 
92
  👚 Each dataset contains product titles, descriptions, and hierarchical product categories with four levels.
93
 
@@ -99,10 +106,10 @@ You can read more about product categorization and its challenges [here](https:/
99
  """
100
 
101
  PRIVATE_MODEL_TEXT = """
102
- [WIP] TabBench Pro currently supports the following models, with more additions planned:
103
  - **Tabular foundation models**: NICL, TabICL, TabPFNv2
104
- - **Tree-based**: XGBoost, CatBoost, LightGBM, Random Forest
105
- - **Neural networks**: MLP, RealMLP, TabM, ModernNCA
106
  """
107
 
108
  PRIVATE_BENCHMARKING_TEXT = """
@@ -116,11 +123,9 @@ For a deeper understanding, you can explore our [Notebooks](https://github.com/N
116
  """
117
 
118
  PRIVATE_METRICS_TEXT = """
119
- [WIP]
120
- TabBench Pro uses different types of metrics to evaluate model performance:
121
  - **Classic metrics**: Accuracy, Precision, Recall, F1 score, AUC
122
- - **Ranking metrics**: Precision@k, Rank, Harmonic Rank, [Elo score?]
123
- - **Industry-relevant metrics**: [ADD WHICH]
124
  """
125
 
126
 
@@ -132,7 +137,8 @@ CITATION_BUTTON_TEXT = """
132
  year={2025},
133
  publisher={GitHub},
134
  url={https://github.com/Neuralk-AI/TabBench}
135
- }"""
 
136
 
137
 
138
  data = {
@@ -184,12 +190,47 @@ def highlight_max(df: pd.DataFrame):
184
  return df.style.apply(style_column, axis=0)
185
 
186
 
187
- with open("public_dummy.json", "r") as f:
188
  public_per_dataset = pd.json_normalize(json.load(f))
189
 
190
- with open("private_dummy.json", "r") as f:
191
  private_per_dataset = pd.json_normalize(json.load(f))
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  # -------------------------
194
  # Leaderboard builder
195
  # -------------------------
@@ -226,6 +267,10 @@ df_comparison = pd.DataFrame(data)
226
  # Gradio UI
227
  # -------------------------
228
  css = """
 
 
 
 
229
  .lg {
230
  font-size: 14px;
231
  }
@@ -308,25 +353,63 @@ def df_to_wrapped_html(df: pd.DataFrame):
308
  html += '</table>'
309
  return html
310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
 
312
- with gr.Blocks(css=css) as demo:
313
- # Sidemenu for benchmark selection
314
- with gr.Sidebar():
315
- gr.Markdown("### Select benchmark")
316
- home_btn = gr.Button("🏡 Home", elem_classes=["white-btn", "selected-btn"])
317
- # gr.Markdown("---")
318
 
319
- public_btn = gr.Button("🌐 TabBench public", elem_classes=["white-btn"])
320
- with gr.Column():
321
- with gr.Accordion("Industry specific ", open=False):
322
- domain_retail_btn = gr.Button("🛍️ Retail", elem_classes=["white-btn"])
323
- domain_finance_btn = gr.Button("💰 Finance", elem_classes=["white-btn"])
324
- domain_healthcare_btn = gr.Button("🏥 Healthcare", elem_classes=["white-btn"])
325
- # gr.Markdown("---")
326
 
327
- private_btn = gr.Button("💼 TabBench Pro ", elem_classes=["white-btn"])
 
 
 
 
 
328
 
329
- datamap_btn = gr.Button("🗺️ Data mapping", elem_classes=["white-btn"])
 
 
 
 
 
 
 
 
 
 
 
 
330
 
331
 
332
 
@@ -337,42 +420,80 @@ with gr.Blocks(css=css) as demo:
337
  # gr.Markdown("---")
338
  gr.Markdown(INTRODUCTION_TEXT)
339
  gr.Markdown(" ")
340
- with gr.Row():
341
- with gr.Column():
342
- gr.Markdown("## ⚡ The TabBench Evaluation Suite")
343
- gr.Markdown(
344
- """
345
- While useful for research, academic benchmarks rarely capture the challenges faced in industry, offering teams little guidance on which models to trust in production (see comparison table 👉).
346
-
347
- TabBench bridges this gap with an evaluation suite designed with industry challenges in mind, making it easier for teams across different sectors to identify the best models for their real-world needs.
348
- """
349
- )
350
- # """
351
- # While academic benchmarks for ML on tabular data offer useful insights for researchers, they rarely capture the challenges industry teams face, like messy data, complex pipelines and the need for deployment readiness.
352
-
353
- # This makes it hard to translate benchmark results into real-world impact and gives industry practitioners little clarity on which models to trust.
354
-
355
- # TabBench bridges this gap with an evaluation suite designed with industry challenges in mind, making it easier for teams across sectors to evaluate which models perform best in practice.
356
- # """
357
 
358
- gr.Markdown("### Features")
359
- with gr.Accordion("🌐 TabBench Public", open=False):
360
- gr.Markdown(PUBLIC_BENCHMARK_TEXT)
361
- with gr.Accordion("💼 TabBench Pro", open=False):
362
- gr.Markdown(PRIVATE_BENCHMARK_TEXT)
363
- with gr.Accordion("🗺️ Data landscape mapping", open=False):
364
- gr.Markdown(DATA_MAP_TEXT)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
 
366
- with gr.Column():
367
- wrapped_table_html = df_to_wrapped_html(df_comparison)
368
- gr.Markdown(wrapped_table_html)
369
- # ,gr.DataFrame(df_comparison, interactive=False, wrap=True, type="pandas")
 
 
370
 
 
 
 
 
 
 
371
 
372
  public_content = gr.Column(visible=False)
373
  with public_content:
374
- label_md = gr.Markdown("## 🥇 TabBench Public Leaderboard - All Industries")
375
-
376
  gr.Markdown('### Features')
377
  # -------------------------
378
  # Top row: Models & Datasets
@@ -436,96 +557,123 @@ with gr.Blocks(css=css) as demo:
436
  gr.Markdown(f"Estimated average model performance over {num_unique_datasets} datasets.")
437
  # Use per-model averages for leaderboard, allow filtering by model_type
438
  per_model_leaderboard = init_leaderboard(public_model_agg, include_model_type_filter=True, industry_filter=False)
439
-
 
440
  with gr.Tab("📊 Performance by dataset"):
441
- gr.Markdown("[WIP - Update with correct dataset industries and targets]")
442
- # Merge public_per_dataset with datasets_info for rich dataset metadata
443
  with open("public_datasets_info.json", "r") as f:
444
  public_datasets_info = pd.DataFrame(json.load(f))
 
445
  public_per_dataset_merged = public_per_dataset.merge(
446
  public_datasets_info,
447
  left_on=["dataset_name", "dataset_id"],
448
  right_on=["dataset_name", "dataset_id"],
449
  how="left"
450
  )
451
- # Set industry directly from public_datasets_info.json
452
- public_per_dataset_merged['industry'] = public_per_dataset_merged['dataset_industry']
453
 
454
- public_per_dataset_merged = public_per_dataset_merged.dropna(subset=['industry'])
 
 
 
 
 
 
455
 
456
- dataset_perf_cols = [
457
- "dataset_name", "dataset_id", "industry", "dataset_target", "model", "Accuracy", "Precision", "Recall", "F1_score", "AUC", "Elo_score",
458
- "num_rows", "num_features", "num_classes", "imbalance_ratio", "missing_values", "categorical_features_ratio"
459
- ]
460
- show_cols = [col for col in dataset_perf_cols] #if col in public_per_dataset_merged.columns]
461
- # Slider for filtering by number of features
462
- min_num_features = int(public_per_dataset_merged['num_features'].min())
463
- max_num_features = int(public_per_dataset_merged['num_features'].max())
464
  with gr.Row():
465
  with gr.Column():
466
  features_slider = gr.Slider(
467
- minimum=min_num_features,
468
- maximum=max_num_features,
469
- value=min_num_features,
470
  step=1,
471
  label="Min Number of Features",
472
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
  with gr.Column():
474
- min_num_classes = int(public_per_dataset_merged['num_classes'].min())
475
- max_num_classes = int(public_per_dataset_merged['num_classes'].max())
476
- with gr.Row():
477
- classes_slider = gr.Slider(
478
- minimum=min_num_classes,
479
- maximum=max_num_classes,
480
- value=min_num_classes,
481
- step=1,
482
- label="Min Number of Classes",
483
- )
484
-
485
- # Add model filter to leaderboard
486
- public_per_dataset_leaderboard = Leaderboard(
487
- value=public_per_dataset_merged[show_cols],
488
- datatype=["str"] + ["number"] * (len(show_cols) - 1),
489
- select_columns=SelectColumns(
490
- default_selection=show_cols,
491
- cant_deselect=["model"] if "model" in show_cols else [],
492
- label="Select Columns to Display:",
493
- ),
494
- search_columns=["dataset_name"] if "dataset_name" in show_cols else [],
495
- hide_columns=[],
496
- filter_columns=[
497
- ColumnFilter("model", type="checkboxgroup", label="🤖 Model"),
498
- ColumnFilter("industry", type="checkboxgroup", label="🏭 Industry"),
499
- ],
500
- interactive=False,
501
- )
502
 
503
- def public_filter_per_dataset_leaderboard(min_features, min_classes):
504
  filtered = public_per_dataset_merged[
505
- (public_per_dataset_merged['num_features'] >= min_features) &
506
- (public_per_dataset_merged['num_classes'] >= min_classes)
 
 
507
  ]
508
- return filtered[show_cols]
509
 
510
- features_slider.change(
511
- fn=lambda min_f, min_c: public_filter_per_dataset_leaderboard(min_f, min_c),
512
- inputs=[features_slider, classes_slider],
513
- outputs=public_per_dataset_leaderboard
514
- )
515
- classes_slider.change(
516
- fn=lambda min_f, min_c: public_filter_per_dataset_leaderboard(min_f, min_c),
517
- inputs=[features_slider, classes_slider],
518
- outputs=public_per_dataset_leaderboard
 
 
 
 
 
 
 
 
 
 
 
 
 
 
519
  )
520
 
 
 
 
 
 
 
 
 
 
521
 
522
  def make_domain_content(industry, label, public_per_dataset, public_datasets_info, model_info):
523
  domain_content = gr.Column(visible=False)
524
  with domain_content:
 
525
  gr.Markdown(f"## 🥇 {label} Benchmark Leaderboard")
526
- # Do not filter by industry here; industry is only available after merging with public_datasets_info.json
527
- # domain_per_dataset = public_per_dataset.copy()
528
- # Filter datasets for this industry first
529
  domain_per_dataset = public_per_dataset.merge(
530
  public_datasets_info[['dataset_name', 'dataset_id', 'dataset_industry']],
531
  on=['dataset_name', 'dataset_id'],
@@ -533,15 +681,12 @@ with gr.Blocks(css=css) as demo:
533
  )
534
  domain_per_dataset = domain_per_dataset[domain_per_dataset['dataset_industry'] == industry]
535
 
536
- with open("model_info.json", "r") as f:
537
- model_info = pd.DataFrame(json.load(f))
538
- # Compute model overview for the industry
539
  model_agg = domain_per_dataset.groupby('model')[['Accuracy', 'Precision', 'Recall', 'F1_score', 'AUC', 'Elo_score']].mean().reset_index()
540
  model_agg = model_agg.round(3)
541
  model_agg = model_agg.merge(model_info[["model_name", "model_type"]], left_on="model", right_on="model_name", how="left").drop(columns=["model_name"])
542
  cols = ["model", "model_type"] + [c for c in model_agg.columns if c not in ["model", "model_type"]]
543
  model_agg = model_agg[cols]
544
- # Sort so NICL is always first
545
  model_agg = model_agg.sort_values(by=["model"], key=lambda x: x != "NICL").reset_index(drop=True)
546
  gr.DataFrame(
547
  value=highlight_max(model_agg),
@@ -550,53 +695,62 @@ with gr.Blocks(css=css) as demo:
550
  type="pandas",
551
  )
552
 
553
- gr.Markdown("## 🔍 Explore more and filter")
554
- # Merge per_dataset with datasets_info for rich dataset metadata
555
- with open("public_datasets_info.json", "r") as f:
556
- public_datasets_info = pd.DataFrame(json.load(f))
557
 
 
558
  domain_per_dataset_merged = domain_per_dataset.merge(
559
  public_datasets_info,
560
  left_on=["dataset_name", "dataset_id"],
561
  right_on=["dataset_name", "dataset_id"],
562
  how="left"
563
  )
564
- print(domain_per_dataset_merged.columns)
565
- # Set industry directly from public_datasets_info.json
566
  domain_per_dataset_merged['industry'] = domain_per_dataset_merged['dataset_industry_y']
567
- # Filter for the correct industry only
568
  domain_per_dataset_merged = domain_per_dataset_merged[domain_per_dataset_merged['industry'] == industry]
569
- num_unique_datasets = domain_per_dataset_merged['dataset_name'].nunique() if 'dataset_name' in domain_per_dataset_merged.columns else 0
570
-
571
- with gr.Tabs() as tabs:
572
- with gr.Tab("🤖 Average model performance"):
573
- gr.Markdown(f"Estimated average model performance over {num_unique_datasets} datasets.")
574
- model_leaderboard = init_leaderboard(model_agg, include_model_type_filter=True, industry_filter=False)
575
-
576
- with gr.Tab("📊 Performance by dataset"):
577
- dataset_perf_cols = [
578
- "dataset_name", "dataset_id", "industry", "dataset_target", "model", "Accuracy", "Precision", "Recall", "F1_score", "AUC", "Elo_score",
579
- "num_rows", "num_features", "num_classes", "imbalance_ratio", "missing_values", "categorical_features_ratio"
580
- ]
581
- show_cols = [col for col in dataset_perf_cols if col in domain_per_dataset_merged.columns]
582
- # Add model filter just like in TabBench Public
583
- per_dataset_leaderboard = Leaderboard(
584
- value=domain_per_dataset_merged[show_cols],
585
- datatype=["str"] + ["number"] * (len(show_cols) - 1),
586
- select_columns=SelectColumns(
587
- default_selection=show_cols,
588
- cant_deselect=["model"] if "model" in show_cols else [],
589
- label="Select Columns to Display:",
590
- ),
591
- search_columns=["dataset_name"] if "dataset_name" in show_cols else [],
592
- hide_columns=[],
593
- filter_columns=[
594
- ColumnFilter("model", type="checkboxgroup", label="🤖 Model"),
595
- ],
596
- interactive=False,
597
- )
598
 
599
- return domain_content
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
 
601
  with open("public_datasets_info.json", "r") as f:
602
  public_datasets_info = pd.DataFrame(json.load(f))
@@ -604,14 +758,25 @@ with gr.Blocks(css=css) as demo:
604
  with open("model_info.json", "r") as f:
605
  model_info = pd.DataFrame(json.load(f))
606
 
607
- retail_domain_content = make_domain_content('Retail', 'Retail', public_per_dataset, public_datasets_info, model_info)
608
- finance_domain_content = make_domain_content('Finance/insurance', 'Finance/insurance', public_per_dataset, public_datasets_info, model_info)
609
- healthcare_domain_content = make_domain_content('Healthcare', 'Healthcare', public_per_dataset, public_datasets_info, model_info)
610
 
611
  private_content = gr.Column(visible=False)
612
  with private_content:
613
- label_md2 = gr.Markdown("## 🥇 TabBench Pro Leaderboard")
614
-
 
 
 
 
 
 
 
 
 
 
 
615
  gr.Markdown('### Features')
616
  # -------------------------
617
  # Top row: Models & Datasets
@@ -666,134 +831,216 @@ with gr.Blocks(css=css) as demo:
666
  wrap=True,
667
  type="pandas",
668
  )
669
- gr.Markdown("## 🔍 Explore more and filter")
670
- with gr.Tabs() as tabs:
671
- with gr.Tab("🤖 Average model performance"):
672
- # Count unique datasets by id used for model performance
673
- num_unique_datasets = private_per_dataset['dataset_id'].nunique() if 'dataset_id' in private_per_dataset.columns else 0
674
- gr.Markdown(f"Estimated average model performance over {num_unique_datasets} datasets.")
675
- # Use per-model averages for leaderboard, allow filtering by model_type
676
- per_model_leaderboard = init_leaderboard(private_model_agg, include_model_type_filter=True, industry_filter=False)
677
- with gr.Tab("📊 Performance by dataset"):
678
- # Merge private_per_dataset with datasets_info for rich dataset metadata
679
- with open("private_datasets_info.json", "r") as f:
680
- private_datasets_info = pd.DataFrame(json.load(f))
681
- private_per_dataset_merged = private_per_dataset.merge(
682
- private_datasets_info,
683
- left_on=["dataset_name", "dataset_id"],
684
- right_on=["dataset_name", "dataset_id"],
685
- how="left"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
686
  )
687
- # Set industry directly from private_datasets_info.json
688
- private_per_dataset_merged['industry'] = private_per_dataset_merged['dataset_industry']
689
- dataset_perf_cols = [
690
- "dataset_name", "dataset_id", "industry", "dataset_target", "model", "Accuracy", "Precision", "Recall", "F1_score", "AUC", "Elo_score",
691
- "num_rows", "num_features", "num_classes", "imbalance_ratio", "missing_values", "categorical_features_ratio"
692
- ]
693
- show_cols = [col for col in dataset_perf_cols] #if col in private_per_dataset_merged.columns]
694
 
695
- # Slider for filtering by number of features
696
- min_num_features = int(private_per_dataset_merged['num_features'].min())
697
- max_num_features = int(private_per_dataset_merged['num_features'].max())
698
- with gr.Row():
699
- with gr.Column():
700
- features_slider = gr.Slider(
701
- minimum=min_num_features,
702
- maximum=max_num_features,
703
- value=min_num_features,
704
- step=1,
705
- label="Min Number of Features",
706
- )
707
- with gr.Column():
708
- min_num_classes = int(private_per_dataset_merged['num_classes'].min())
709
- max_num_classes = int(private_per_dataset_merged['num_classes'].max())
710
- with gr.Row():
711
- classes_slider = gr.Slider(
712
- minimum=min_num_classes,
713
- maximum=max_num_classes,
714
- value=min_num_classes,
715
- step=1,
716
- label="Min Number of Classes",
717
- )
718
-
719
- # Add model filter to leaderboard
720
- private_per_dataset_leaderboard = Leaderboard(
721
- value=private_per_dataset_merged[show_cols],
722
- datatype=["str"] + ["number"] * (len(show_cols) - 1),
723
- select_columns=SelectColumns(
724
- default_selection=show_cols,
725
- cant_deselect=["model"] if "model" in show_cols else [],
726
- label="Select Columns to Display:",
727
- ),
728
- search_columns=["dataset_name"] if "dataset_name" in show_cols else [],
729
- hide_columns=[],
730
- filter_columns=[
731
- ColumnFilter("model", type="checkboxgroup", label="🤖 Model"),
732
- ColumnFilter("industry", type="checkboxgroup", label="🏭 Industry"),
733
- ],
734
- interactive=False,
735
  )
736
 
737
- def filter_per_dataset_leaderboard(min_features, min_classes):
738
- filtered = private_per_dataset_merged[
739
- (private_per_dataset_merged['num_features'] >= min_features) &
740
- (private_per_dataset_merged['num_classes'] >= min_classes)
741
- ]
742
- return filtered[show_cols]
 
 
 
743
 
744
- features_slider.change(
745
- fn=lambda min_f, min_c: filter_per_dataset_leaderboard(min_f, min_c),
746
- inputs=[features_slider, classes_slider],
747
- outputs=private_per_dataset_leaderboard
 
 
 
 
 
 
748
  )
749
- classes_slider.change(
750
- fn=lambda min_f, min_c: filter_per_dataset_leaderboard(min_f, min_c),
751
- inputs=[features_slider, classes_slider],
752
- outputs=private_per_dataset_leaderboard
 
 
753
  )
754
 
755
- datamap_content = gr.Column(visible=False)
756
- with datamap_content:
757
- gr.Markdown("# 🗺️ Data mapping")
758
-
759
- # gr.Markdown("## 📊 Public vs Private Dataset Statistics Comparison")
760
-
761
- # Select numeric columns to compare
762
- compare_columns = [
763
- # "num_rows",
764
- # "num_features",
765
- "num_classes",
766
- "imbalance_ratio",
767
- "skewness",
768
- "frobenius_norm",
769
- "min_eigenvalue"
770
- ]
771
 
772
- # Compute summary stats for both dataset groups
773
- public_summary = public_datasets_info[compare_columns].describe().loc[["mean", "std"]]
774
- private_summary = private_datasets_info[compare_columns].describe().loc[["mean", "std"]]
 
 
 
775
 
776
- # Combine into a single comparison DataFrame
777
- comparison_df = pd.DataFrame({
778
- "Statistic": compare_columns,
779
- "🌐 Public Mean": [public_summary.loc["mean", c] for c in compare_columns],
780
- "🌐 Public Std": [public_summary.loc["std", c] for c in compare_columns],
781
- "💼 Industry Mean": [private_summary.loc["mean", c] for c in compare_columns],
782
- "💼 Industry Std": [private_summary.loc["std", c] for c in compare_columns],
783
- })
784
 
785
- # Round numbers and clean up formatting
786
- comparison_df = comparison_df.round(3)
 
 
 
 
787
 
788
- gr.Markdown("Below is a comparison of average dataset characteristics between **public** and **private (industry)** datasets. These stats help visualize how academic benchmarks differ from real-world data distributions.")
 
 
 
 
 
 
789
 
790
- gr.DataFrame(
791
- value=comparison_df,
 
 
 
 
 
 
792
  interactive=False,
793
- wrap=True,
794
  type="pandas",
 
795
  )
796
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
797
  # # Optional: visual comparison chart
798
  # with gr.Accordion("📈 Visualize Differences", open=False):
799
 
@@ -829,7 +1076,8 @@ with gr.Blocks(css=css) as demo:
829
  def show_content(visible_content, selected_btn):
830
  # All content blocks and buttons
831
  content_blocks = [home_intro, public_content, retail_domain_content, finance_domain_content, healthcare_domain_content, private_content, datamap_content]
832
- btns = [home_btn, public_btn, domain_retail_btn, domain_finance_btn, domain_healthcare_btn, private_btn, datamap_btn]
 
833
  # Set visibility
834
  updates = {block: gr.update(visible=(block == visible_content)) for block in content_blocks}
835
  # Set button classes
@@ -841,35 +1089,50 @@ with gr.Blocks(css=css) as demo:
841
  return updates
842
 
843
  def show_home():
844
- return show_content(home_intro, home_btn)
845
 
846
  def show_public():
847
- return show_content(public_content, public_btn)
848
  def show_demain_retail():
849
- return show_content(retail_domain_content, domain_retail_btn)
850
  def show_domain_finance():
851
- return show_content(finance_domain_content, domain_finance_btn)
852
  def show_domain_healthcare():
853
- return show_content(healthcare_domain_content, domain_healthcare_btn)
854
 
855
  def show_private():
856
- return show_content(private_content, private_btn)
857
 
858
  def show_datamap():
859
- return show_content(datamap_content, datamap_btn)
860
 
861
 
862
- outputs = [home_intro, public_content, retail_domain_content, finance_domain_content, healthcare_domain_content, private_content, datamap_content, home_btn, public_btn, domain_retail_btn, domain_finance_btn, domain_healthcare_btn, private_btn, datamap_btn]
863
- home_btn.click(fn=show_home, inputs=None, outputs=outputs)
864
-
865
- public_btn.click(fn=show_public, inputs=None, outputs=outputs)
866
- domain_retail_btn.click(fn=show_demain_retail, inputs=None, outputs=outputs)
867
- domain_finance_btn.click(fn=show_domain_finance, inputs=None, outputs=outputs)
868
- domain_healthcare_btn.click(fn=show_domain_healthcare, inputs=None, outputs=outputs)
 
 
 
869
 
870
- private_btn.click(fn=show_private, inputs=None, outputs=outputs)
 
 
 
871
 
872
- datamap_btn.click(fn=show_datamap, inputs=None, outputs=outputs)
 
 
 
 
 
 
873
 
 
 
 
874
 
875
- demo.launch(ssr_mode=False)
 
5
  import json
6
  import random
7
 
8
+ import plotly.express as px
9
+ import seaborn as sns
10
+ from io import BytesIO
11
+ import base64
12
+
13
  # TabBench currently supports the following models, with new additions that keep coming:
14
  # - **NICL (Neuralk In-Context-Learning)**: Our in-house tabular foundation model based on an in-context learning architecture (proprietary).
15
  # - **TabICL**: A transformer-based model that performs feature compression before doing in-context learning on tabular data by conditioning on labeled support examples to predict unseen queries without task-specific training.
 
17
  # - **XGBoost**: An optimized distributed gradient boosting library designed to be highly efficient, flexible, and portable.
18
  # - **CatBoost**: A gradient boosting on decision trees library, particularly strong with categorical features.
19
  # - **LightGBM**: A fast gradient boosting framework that builds decision trees using histogram-based learning for scalable, high-performance tabular modeling.
 
 
20
  # - **ModernNCA**: An advanced extension of Neighborhood Component Analysis (NCA) that employs deep neural networks with stochastic neighborhood sampling to learn complex feature interactions for tabular data.
21
  # - **RealMLP**: An enhanced MLP optimized with strong default parameters, achieving competitive performance on tabular data.
22
  # - **TabM**: A deep learning model that efficiently imitates an ensemble of MLPs, enhancing performance on tabular data tasks without the overhead of training multiple models.
23
  # It is capable of processing datasets up to 100× larger and running up to 10× faster than TabPFNv2.
24
 
25
  PUBLIC_DATASETS_TEXT = """
26
+ We curate a list of **195 datasets** from OpenML that span various industries such as **retail, healthcare, finance, and more**.
27
 
28
  🔎 You can easily filter datasets by industry below or explore the industry specific leaderboards via the sidebar.
29
  """
 
31
  MODELS_TEXT = """
32
  TabBench currently supports the following models, with more additions planned:
33
  - **Tabular foundation models**: NICL, TabICL, TabPFNv2
34
+ - **Tree-based**: XGBoost, CatBoost, LightGBM
35
+ - **Neural networks**: RealMLP, TabM, ModernNCA
36
+
37
+ __Note__ : Tree-based models are also ensembled according to best practices.
38
  """
39
 
40
  BENCHMARKING_TEXT = """
 
52
  METRICS_TEXT = """
53
  TabBench uses different types of metrics to evaluate model performance:
54
  - **Classic metrics**: Accuracy, Precision, Recall, F1 score, AUC
55
+ - **Ranking metrics**: Rank, Elo score
 
56
  """
57
 
58
  TITLE = """
59
+ <div style="display:flex; text-align:center">
60
+ <h1 style="margin:0; font-size:34px; font-weight:600;">
61
+ <span style="color:#25ccb9; font-style: bold;">TabBench</span>
62
+ <span>
63
+ : An Industry Benchmark for Tabular Machine Learning
64
+ </span>
65
+ </h1>
66
+ </div>
67
+
68
  """
69
 
70
  INTRODUCTION_TEXT = """
71
+ <p style="font-size: 16px; text-align:center; font-style: italic;">
72
  Bridging the gap between academic benchmarks and industry needs
73
  </p>
74
  """
75
 
76
  DATA_MAP_TEXT = """
77
+ - 🔎 **Explore different settings of dataset generation**
78
+ - 📈 **Compare Tabular Foundation Models on specific situations and identify strengths & weaknesses**
79
  """
80
 
81
  PUBLIC_BENCHMARK_TEXT = """
82
+ - 📊 **A curation of 195 public datasets** across industries such as retail, healthcare, finance, energy, etc
83
  - 🤖 **Evaluations on 10+ powerful models** from gradient boosting and decision trees to tabular foundation models
84
  - 💥 **Integration of NICL**, the Neuralk AI tabular foundation model designed for industry-grade use cases
85
  - 🏅 **Leaderboards by sector** to discover which models perform best for each industry
 
94
  # rewrite new uses continuously being added
95
 
96
  PRIVATE_DATA_TEXT = """
97
+ We curate a list of **63 proprietary datasets** from different retailers focused on the **use case of product categorization**.
98
 
99
  👚 Each dataset contains product titles, descriptions, and hierarchical product categories with four levels.
100
 
 
106
  """
107
 
108
  PRIVATE_MODEL_TEXT = """
109
+ TabBench Enterprise currently supports the following models, with more additions planned:
110
  - **Tabular foundation models**: NICL, TabICL, TabPFNv2
111
+ - **Tree-based**: XGBoost
112
+ - **Neural networks**: RealMLP, TabM, ModernNCA
113
  """
114
 
115
  PRIVATE_BENCHMARKING_TEXT = """
 
123
  """
124
 
125
  PRIVATE_METRICS_TEXT = """
126
+ TabBench Enterprise uses different types of metrics to evaluate model performance:
 
127
  - **Classic metrics**: Accuracy, Precision, Recall, F1 score, AUC
128
+ - **Ranking metrics**: Rank, Elo score
 
129
  """
130
 
131
 
 
137
  year={2025},
138
  publisher={GitHub},
139
  url={https://github.com/Neuralk-AI/TabBench}
140
+ }
141
+ """
142
 
143
 
144
  data = {
 
190
  return df.style.apply(style_column, axis=0)
191
 
192
 
193
+ with open("complete_results_acad.json", "r") as f:
194
  public_per_dataset = pd.json_normalize(json.load(f))
195
 
196
+ with open("complete_results_indus.json", "r") as f:
197
  private_per_dataset = pd.json_normalize(json.load(f))
198
 
199
+ with open("qrt.json", "r") as f:
200
+ qrt_scores = json.load(f)
201
+
202
+ # Suppose qrt_scores is a dict like {"NICL": 0.8, "TabPFNv2": 0.6, "XGBoost": 0.5}
203
+ models = ["Models"]+ list(qrt_scores.keys())
204
+ accuracies = ["Test Accuracy"] + list(qrt_scores.values())
205
+
206
+ # Create a DataFrame with two rows: "Model" and "Test Accuracy"
207
+ df_qrt = pd.DataFrame([accuracies], index=["Test Accuracy"], columns=models)
208
+
209
+ # Optional: highlight best accuracy
210
+ def highlight_best_qrt(df):
211
+ styles = pd.DataFrame("", index=df.index, columns=df.columns)
212
+ styles.loc["Test Accuracy", df.loc["Test Accuracy"] == 51.7] = "background-color: gold; color: black;"
213
+ styles.loc["Test Accuracy", df.loc["Test Accuracy"] == 51.58] = "background-color: #a6a6a6; color: black;"
214
+ styles.loc["Test Accuracy", df.loc["Test Accuracy"] == 51.18] = "background-color: #ad5803; color: black;"
215
+ return styles
216
+
217
+ styled_df_qrt = df_qrt.style.apply(highlight_best_qrt, axis=None)
218
+
219
+ def add_top3_ranks(df, metric_cols):
220
+ df = df.copy()
221
+
222
+ for col in metric_cols:
223
+ if col not in df.columns:
224
+ continue
225
+
226
+ ranks = df[col].rank(ascending=False, method="min")
227
+
228
+ df[f"{col}_rank"] = ranks.map(
229
+ lambda r: "🥇" if r == 1 else "🥈" if r == 2 else "🥉" if r == 3 else ""
230
+ )
231
+
232
+ return df
233
+
234
  # -------------------------
235
  # Leaderboard builder
236
  # -------------------------
 
267
  # Gradio UI
268
  # -------------------------
269
  css = """
270
+ :root {
271
+ color-scheme: light;
272
+ }
273
+
274
  .lg {
275
  font-size: 14px;
276
  }
 
353
  html += '</table>'
354
  return html
355
 
356
+ def plot_global_model_ranking_plotly(df, metric="Accuracy"):
357
+ import plotly.graph_objects as go
358
+
359
+ df_sorted = df.sort_values(metric, ascending=True).reset_index(drop=True)
360
+ x_max = df_sorted[metric].max() * 1.1 # 10% buffer
361
+
362
+ fig = go.Figure(go.Bar(
363
+ x=df_sorted[metric],
364
+ y=df_sorted['model'],
365
+ orientation='h',
366
+ text=df_sorted[metric],
367
+ textposition='inside',
368
+ marker=dict(
369
+ color=df_sorted[metric],
370
+ colorscale='Viridis',
371
+ showscale=False
372
+ )
373
+ ))
374
+
375
+ fig.update_layout(
376
+ template="plotly_white",
377
+ plot_bgcolor="white",
378
+ paper_bgcolor="white",
379
+ xaxis=dict(title=metric, automargin=True, range=[0, x_max]),
380
+ yaxis=dict(title="Model", automargin=True),
381
+ height=100 + 40 * len(df_sorted),
382
+ margin=dict(l=180, r=40, t=60, b=40),
383
+ )
384
 
385
+ return fig
 
 
 
 
 
386
 
387
+ def update_ranking_plot(metric):
388
+ return plot_global_model_ranking_plotly(
389
+ public_model_agg,
390
+ metric=metric
391
+ )
 
 
392
 
393
+ with gr.Blocks(css=css, theme=gr.themes.Default()) as demo:
394
+ # # Sidemenu for benchmark selection
395
+ # with gr.Sidebar(visible=True) as sidebar:
396
+ # gr.Markdown("### Select benchmark")
397
+ # home_btn = gr.Button("🏡 Home", elem_classes=["white-btn", "selected-btn"])
398
+ # # gr.Markdown("---")
399
 
400
+ # public_btn = gr.Button("🌐 TabBench public", elem_classes=["white-btn"])
401
+ # private_btn = gr.Button("💼 TabBench Enterprise ", elem_classes=["white-btn"])
402
+
403
+ # with gr.Column():
404
+ # with gr.Accordion("🔍 Search by Industry", open=False):
405
+ # domain_retail_btn = gr.Button("🛍️ Retail", elem_classes=["white-btn"])
406
+ # domain_finance_btn = gr.Button("💰 Finance", elem_classes=["white-btn"])
407
+ # domain_healthcare_btn = gr.Button("🏥 Healthcare", elem_classes=["white-btn"])
408
+ # # gr.Markdown("---")
409
+
410
+
411
+
412
+ # datamap_btn = gr.Button("🗺️ Data mapping", elem_classes=["white-btn"])
413
 
414
 
415
 
 
420
  # gr.Markdown("---")
421
  gr.Markdown(INTRODUCTION_TEXT)
422
  gr.Markdown(" ")
423
+ with gr.Column():
424
+ gr.Markdown("## ⚡ Why TabBench ?")
425
+ gr.Markdown(
426
+ """
427
+ While useful for research, academic benchmarks rarely capture the challenges faced in industry, offering teams little guidance on which models to trust in production.
428
+
429
+ TabBench is the first Open Source benchmark designed to test both Predictive Foundation Models and Traditional ML Models on real Enterprise data and use cases, Unlike most benchmarks, TabBench evaluates models on real-world scenarios across industries, helping Data scientists confidently choose the models that work best in production, not just in theory.
430
+ Real-workd data is complex, messy and high-dimensional; TabBench is particularly useful in showcasing the performance of SOTA Predictive Foundation models as well as traditional ML tools in this context.
431
+ """
432
+ )
 
 
 
 
 
 
 
433
 
434
+ gr.Markdown(' ')
435
+ gr.Markdown("## 🚀 Search by Benchmark Type")
436
+ with gr.Row():
437
+ with gr.Column():
438
+ with gr.Accordion("🌐 TabBench Public", open=False):
439
+ gr.Markdown(PUBLIC_BENCHMARK_TEXT)
440
+ public_btn_home = gr.Button("Go to TabBench Public", elem_classes=["white-btn"])
441
+ with gr.Column():
442
+ with gr.Accordion("💼 TabBench Enterprise", open=False):
443
+ gr.Markdown(PRIVATE_BENCHMARK_TEXT)
444
+ private_btn_home = gr.Button("Go to TabBench Enterprise", elem_classes=["white-btn"])
445
+ with gr.Column():
446
+ with gr.Accordion("🤖 Understanding Tabular Foundation Models", open=False):
447
+ gr.Markdown(DATA_MAP_TEXT)
448
+ datamap_btn_home = gr.Button("Go to TabFMs space", elem_classes=["white-btn"])
449
+ # ,gr.DataFrame(df_comparison, interactive=False, wrap=True, type="pandas")
450
+
451
+ public_model_agg = public_per_dataset.groupby('model')[['Accuracy', 'Precision', 'Recall', 'F1_score', 'AUC', 'Elo_score']].mean().reset_index()
452
+ public_model_agg = public_model_agg.round(3)
453
+ # ranking_fig = plot_global_model_ranking_plotly(public_model_agg, metric="Accuracy")
454
+ # Search by industry section
455
+ gr.Markdown(' ')
456
+ gr.Markdown("## 🔍 Search by Industry")
457
+ with gr.Row():
458
+ finance_btn_home = gr.Button("💰 Finance", elem_classes=["white-btn"])
459
+ healthcare_btn_home = gr.Button("🏥 Healthcare", elem_classes=["white-btn"])
460
+ retail_btn_home = gr.Button("🛍️ Retail", elem_classes=["white-btn"])
461
+
462
+ gr.Markdown(' ')
463
+ gr.Markdown("## 🏆 Overview of the Leaderboard *(Evaluation on Public Datasets)*")
464
+ gr.Markdown(' ')
465
+ # ranking_fig = plot_global_model_ranking_plotly(
466
+ # public_model_agg,
467
+ # metric="Accuracy",
468
+ # )
469
+
470
+ # gr.Plot(ranking_fig)
471
+
472
+ with gr.Row():
473
+ metric_selector = gr.Dropdown(
474
+ choices=["Accuracy", "Precision", "Recall", "F1_score", "AUC", "Elo_score"],
475
+ value="Accuracy",
476
+ label="📊 Metric to display"
477
+ )
478
 
479
+ ranking_plot = gr.Plot(
480
+ value=plot_global_model_ranking_plotly(
481
+ public_model_agg,
482
+ metric="Accuracy"
483
+ )
484
+ )
485
 
486
+ metric_selector.change(
487
+ fn=update_ranking_plot,
488
+ inputs=metric_selector,
489
+ outputs=ranking_plot
490
+ )
491
+
492
 
493
  public_content = gr.Column(visible=False)
494
  with public_content:
495
+ home_btn_public = gr.Button("🏡 Home", elem_classes=["white-btn", "selected-btn"])
496
+ label_md = gr.Markdown("# 🥇 TabBench Public Leaderboard - All Industries")
497
  gr.Markdown('### Features')
498
  # -------------------------
499
  # Top row: Models & Datasets
 
557
  gr.Markdown(f"Estimated average model performance over {num_unique_datasets} datasets.")
558
  # Use per-model averages for leaderboard, allow filtering by model_type
559
  per_model_leaderboard = init_leaderboard(public_model_agg, include_model_type_filter=True, industry_filter=False)
560
+
561
+
562
  with gr.Tab("📊 Performance by dataset"):
563
+ # Load dataset metadata
 
564
  with open("public_datasets_info.json", "r") as f:
565
  public_datasets_info = pd.DataFrame(json.load(f))
566
+
567
  public_per_dataset_merged = public_per_dataset.merge(
568
  public_datasets_info,
569
  left_on=["dataset_name", "dataset_id"],
570
  right_on=["dataset_name", "dataset_id"],
571
  how="left"
572
  )
 
 
573
 
574
+ public_per_dataset_merged["industry"] = public_per_dataset_merged["dataset_industry"]
575
+ public_per_dataset_merged = public_per_dataset_merged.dropna(subset=["industry"])
576
+
577
+ # --- Sliders and controls ---
578
+ min_features, max_features = int(public_per_dataset_merged["features"].min()), int(public_per_dataset_merged["features"].max())
579
+ min_rows, max_rows = int(public_per_dataset_merged["rows"].min()), int(public_per_dataset_merged["rows"].max())
580
+ min_pct_cat, max_pct_cat = float(public_per_dataset_merged["pct_cat"].min()), float(public_per_dataset_merged["pct_cat"].max())
581
 
 
 
 
 
 
 
 
 
582
  with gr.Row():
583
  with gr.Column():
584
  features_slider = gr.Slider(
585
+ minimum=min_features,
586
+ maximum=max_features,
587
+ value=min_features,
588
  step=1,
589
  label="Min Number of Features",
590
  )
591
+ rows_slider = gr.Slider(
592
+ minimum=min_rows,
593
+ maximum=max_rows,
594
+ value=min_rows,
595
+ step=100,
596
+ label="Min Number of Rows",
597
+ )
598
+ pct_cat_slider = gr.Slider(
599
+ minimum=min_pct_cat,
600
+ maximum=max_pct_cat,
601
+ value=min_pct_cat,
602
+ step=0.01,
603
+ label="Min % Categorical Features",
604
+ )
605
+
606
  with gr.Column():
607
+ task_button = gr.Radio(
608
+ choices=["Binary", "Multi-class"],
609
+ value="Binary",
610
+ label="Task Type",
611
+ )
612
+
613
+ # --- Columns ---
614
+ dataset_perf_cols = [
615
+ "model",
616
+ "Accuracy",
617
+ "Precision",
618
+ "Recall",
619
+ "F1_score",
620
+ "AUC",
621
+ "Elo_score",
622
+ ]
623
+
624
+ # --- Filtering & aggregation ---
625
+ def filter_and_aggregate_models(min_features, min_rows, min_pct_cat, task_type):
626
+ task_val = 0 if task_type == "Binary" else 1
 
 
 
 
 
 
 
 
627
 
 
628
  filtered = public_per_dataset_merged[
629
+ (public_per_dataset_merged["features"] >= min_features)
630
+ & (public_per_dataset_merged["rows"] >= min_rows)
631
+ & (public_per_dataset_merged["pct_cat"] >= min_pct_cat)
632
+ & (public_per_dataset_merged["task"] == task_val)
633
  ]
 
634
 
635
+ if filtered.empty:
636
+ return pd.DataFrame(columns=dataset_perf_cols)
637
+
638
+ per_model_avg = (
639
+ filtered
640
+ .groupby("model")[dataset_perf_cols[1:]]
641
+ .mean()
642
+ .reset_index()
643
+ )
644
+
645
+ return highlight_max(per_model_avg)
646
+
647
+ # --- Styled table ---
648
+ performance_table = gr.DataFrame(
649
+ value=filter_and_aggregate_models(
650
+ min_features,
651
+ min_rows,
652
+ min_pct_cat,
653
+ "Binary",
654
+ ),
655
+ interactive=False,
656
+ wrap=True,
657
+ type="pandas",
658
  )
659
 
660
+ # --- Bind controls ---
661
+ inputs = [features_slider, rows_slider, pct_cat_slider, task_button]
662
+ for control in inputs:
663
+ control.change(
664
+ fn=filter_and_aggregate_models,
665
+ inputs=inputs,
666
+ outputs=performance_table,
667
+ )
668
+
669
 
670
  def make_domain_content(industry, label, public_per_dataset, public_datasets_info, model_info):
671
  domain_content = gr.Column(visible=False)
672
  with domain_content:
673
+ home_btn_domain = gr.Button("🏡 Home", elem_classes=["white-btn", "selected-btn"])
674
  gr.Markdown(f"## 🥇 {label} Benchmark Leaderboard")
675
+
676
+ # Filter datasets for this industry
 
677
  domain_per_dataset = public_per_dataset.merge(
678
  public_datasets_info[['dataset_name', 'dataset_id', 'dataset_industry']],
679
  on=['dataset_name', 'dataset_id'],
 
681
  )
682
  domain_per_dataset = domain_per_dataset[domain_per_dataset['dataset_industry'] == industry]
683
 
684
+ # Compute model overview
 
 
685
  model_agg = domain_per_dataset.groupby('model')[['Accuracy', 'Precision', 'Recall', 'F1_score', 'AUC', 'Elo_score']].mean().reset_index()
686
  model_agg = model_agg.round(3)
687
  model_agg = model_agg.merge(model_info[["model_name", "model_type"]], left_on="model", right_on="model_name", how="left").drop(columns=["model_name"])
688
  cols = ["model", "model_type"] + [c for c in model_agg.columns if c not in ["model", "model_type"]]
689
  model_agg = model_agg[cols]
 
690
  model_agg = model_agg.sort_values(by=["model"], key=lambda x: x != "NICL").reset_index(drop=True)
691
  gr.DataFrame(
692
  value=highlight_max(model_agg),
 
695
  type="pandas",
696
  )
697
 
698
+ gr.Markdown("## 🔍 Explore performance by dataset")
 
 
 
699
 
700
+ # Merge for full dataset info
701
  domain_per_dataset_merged = domain_per_dataset.merge(
702
  public_datasets_info,
703
  left_on=["dataset_name", "dataset_id"],
704
  right_on=["dataset_name", "dataset_id"],
705
  how="left"
706
  )
 
 
707
  domain_per_dataset_merged['industry'] = domain_per_dataset_merged['dataset_industry_y']
 
708
  domain_per_dataset_merged = domain_per_dataset_merged[domain_per_dataset_merged['industry'] == industry]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
709
 
710
+ # Columns for dataset-wise leaderboard
711
+ dataset_perf_cols = [
712
+ "model",
713
+ "Accuracy",
714
+ "Precision",
715
+ "Recall",
716
+ "F1_score",
717
+ "AUC",
718
+ "Elo_score",
719
+ ]
720
+ num_unique_datasets = domain_per_dataset_merged['dataset_id'].nunique() if 'dataset_id' in domain_per_dataset_merged.columns else 0
721
+ gr.Markdown(f"Estimated average model performance over {num_unique_datasets} datasets.")
722
+ # Available datasets
723
+ dataset_ids = sorted(domain_per_dataset_merged["dataset_name"].dropna().unique().tolist())
724
+
725
+ dataset_dropdown = gr.Dropdown(
726
+ choices=dataset_ids,
727
+ label="📂 Select a dataset",
728
+ value=dataset_ids[0] if dataset_ids else None,
729
+ )
730
+
731
+ dataset_leaderboard = gr.DataFrame(
732
+ value=highlight_max(domain_per_dataset_merged[
733
+ domain_per_dataset_merged["dataset_name"] == dataset_ids[0]
734
+ ][dataset_perf_cols]) if dataset_ids else pd.DataFrame(),
735
+ interactive=False,
736
+ wrap=True,
737
+ type="pandas",
738
+ )
739
+
740
+ # Callback to update leaderboard
741
+ def update_dataset_leaderboard(selected_dataset_id):
742
+ return highlight_max(domain_per_dataset_merged[
743
+ domain_per_dataset_merged["dataset_name"] == selected_dataset_id
744
+ ][dataset_perf_cols])
745
+
746
+ dataset_dropdown.change(
747
+ fn=update_dataset_leaderboard,
748
+ inputs=dataset_dropdown,
749
+ outputs=dataset_leaderboard,
750
+ )
751
+
752
+ return domain_content, home_btn_domain
753
+
754
 
755
  with open("public_datasets_info.json", "r") as f:
756
  public_datasets_info = pd.DataFrame(json.load(f))
 
758
  with open("model_info.json", "r") as f:
759
  model_info = pd.DataFrame(json.load(f))
760
 
761
+ retail_domain_content, home_btn_retail = make_domain_content('Retail', 'Retail', public_per_dataset, public_datasets_info, model_info)
762
+ finance_domain_content, home_btn_finance = make_domain_content('Finance/insurance', 'Finance/insurance', public_per_dataset, public_datasets_info, model_info)
763
+ healthcare_domain_content, home_btn_health = make_domain_content('Healthcare', 'Healthcare', public_per_dataset, public_datasets_info, model_info)
764
 
765
  private_content = gr.Column(visible=False)
766
  with private_content:
767
+ home_btn_private = gr.Button("🏡 Home", elem_classes=["white-btn", "selected-btn"])
768
+ label_md2 = gr.Markdown("# 🥇 TabBench Enterprise Leaderboard")
769
+ gr.Markdown("## Example: comparative results on QRT Data Challenge")
770
+ gr.Markdown("" \
771
+ "Qube Research & Technologies (QRT) is a leading global quantitative and systematic investment manager. Their use of real-world business data to sponsor a data challenge with ENS Paris provided a real-world opportunity to highlight the value of Neuralk's Predictive Foundation Models on Enterprise financial data. " \
772
+ "The proposed challenge aimed predicting the return of a stock in the US market using historical data over a recent period of 20 days. More info on the challenge [here](https://challengedata.ens.fr/challenges/23)."
773
+ )
774
+ gr.DataFrame(
775
+ value=styled_df_qrt,
776
+ interactive=False,
777
+ wrap=True,
778
+ type="pandas",
779
+ )
780
  gr.Markdown('### Features')
781
  # -------------------------
782
  # Top row: Models & Datasets
 
831
  wrap=True,
832
  type="pandas",
833
  )
834
+ gr.Markdown("## 🔍 Explore performance by dataset")
835
+
836
+ # Columns to display
837
+ dataset_perf_cols = [
838
+ "model",
839
+ "Accuracy",
840
+ "Precision",
841
+ "Recall",
842
+ "F1_score",
843
+ "AUC",
844
+ "Elo_score",
845
+ ]
846
+
847
+ # Available datasets
848
+ dataset_ids = (
849
+ private_per_dataset["dataset_id"]
850
+ .dropna()
851
+ .unique()
852
+ .tolist()
853
+ )
854
+
855
+ dataset_ids = sorted(dataset_ids)
856
+
857
+ dataset_dropdown = gr.Dropdown(
858
+ choices=dataset_ids,
859
+ label="📂 Select a dataset",
860
+ value=dataset_ids[0],
861
+ )
862
+
863
+ dataset_leaderboard = gr.DataFrame(
864
+ value=highlight_max(private_per_dataset[
865
+ private_per_dataset["dataset_id"] == dataset_ids[0]
866
+ ][dataset_perf_cols]),
867
+ interactive=False,
868
+ wrap=True,
869
+ type="pandas",
870
+ )
871
+
872
+ def update_dataset_leaderboard(selected_dataset_id):
873
+ return highlight_max(private_per_dataset[
874
+ private_per_dataset["dataset_id"] == selected_dataset_id
875
+ ][dataset_perf_cols])
876
+
877
+ dataset_dropdown.change(
878
+ fn=update_dataset_leaderboard,
879
+ inputs=dataset_dropdown,
880
+ outputs=dataset_leaderboard,
881
+ )
882
+
883
+
884
+ datamap_content = gr.Column(visible=False)
885
+ with datamap_content:
886
+ home_btn_datamap = gr.Button("🏡 Home", elem_classes=["white-btn", "selected-btn"])
887
+ gr.Markdown("# 🤖 Understanding tabular Foundation Models")
888
+ gr.Markdown(" ")
889
+ gr.Markdown(
890
+ "Side study using scikit-learn's make_classification data generation function to have an in-depth understanding of Tabular Foundation Models strengths and weaknesses under specific data characteristics.")
891
+
892
+ gr.Markdown('')
893
+ PARQUET_PATH = "make_classif-parameter_space.parquet"
894
+ df_sklearn = pd.read_parquet(PARQUET_PATH)
895
+
896
+ # =====================
897
+ # Basic preprocessing
898
+ # =====================
899
+
900
+ MODEL_COLS = {
901
+ "NICL": "acc_NICL",
902
+ "TABPFN": "acc_TABPFN",
903
+ "TABICL": "acc_TABICL",
904
+ "RF": "acc_RF",
905
+ }
906
+
907
+ # =====================
908
+ # Slider ranges
909
+ # =====================
910
+ min_features, max_features = int(df_sklearn["n_features"].min()), int(df_sklearn["n_features"].max())
911
+ min_samples, max_samples = int(df_sklearn["n_samples"].min()), int(df_sklearn["n_samples"].max())
912
+ min_classes, max_classes = int(df_sklearn["n_classes"].min()), int(df_sklearn["n_classes"].max())
913
+ min_sep, max_sep = float(df_sklearn["class_sep"].min()), float(df_sklearn["class_sep"].max())
914
+
915
+ # =====================
916
+ # Filtering + aggregation
917
+ # =====================
918
+ def filter_and_aggregate(
919
+ f_min, f_max,
920
+ s_min, s_max,
921
+ c_min, c_max,
922
+ sep_min, sep_max,
923
+ ):
924
+ # sécurité si sliders se croisent
925
+ if f_min > f_max or s_min > s_max or c_min > c_max or sep_min > sep_max:
926
+ return (
927
+ pd.DataFrame(columns=["Model", "Accuracy"]),
928
+ "⚠️ Invalid interval selection",
929
  )
 
 
 
 
 
 
 
930
 
931
+ filtered = df_sklearn[
932
+ df_sklearn["n_features"].between(f_min, f_max)
933
+ & df_sklearn["n_samples"].between(s_min, s_max)
934
+ & df_sklearn["n_classes"].between(c_min, c_max)
935
+ & df_sklearn["class_sep"].between(sep_min, sep_max)
936
+ ]
937
+
938
+ n_datasets = len(filtered)
939
+
940
+ if filtered.empty:
941
+ return (
942
+ pd.DataFrame(columns=["Model", "Accuracy"]),
943
+ "⚠️ No datasets match the current filters.",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
944
  )
945
 
946
+ rows = []
947
+ for model, col in MODEL_COLS.items():
948
+ rows.append({
949
+ "Model": model,
950
+ "Accuracy": filtered[col].mean(),
951
+ })
952
+
953
+ out = highlight_max(pd.DataFrame(rows))
954
+ return out, f"📦 **{n_datasets} datasets** considered"
955
 
956
+
957
+ gr.Markdown("## 📊 Average Model Accuracy by Dataset Properties")
958
+
959
+ with gr.Row():
960
+ with gr.Column():
961
+ features_min = gr.Slider(
962
+ min_features, max_features,
963
+ value=min_features,
964
+ step=1,
965
+ label="Min number of features"
966
  )
967
+
968
+ features_max = gr.Slider(
969
+ min_features, max_features,
970
+ value=max_features,
971
+ step=1,
972
+ label="Max number of features"
973
  )
974
 
975
+ with gr.Column():
976
+ samples_min = gr.Slider(
977
+ min_samples, max_samples,
978
+ value=min_samples,
979
+ step=10,
980
+ label="Min number of samples"
981
+ )
 
 
 
 
 
 
 
 
 
982
 
983
+ samples_max = gr.Slider(
984
+ min_samples, max_samples,
985
+ value=max_samples,
986
+ step=10,
987
+ label="Max number of samples"
988
+ )
989
 
990
+ with gr.Column():
991
+ classes_min = gr.Slider(
992
+ min_classes, max_classes,
993
+ value=min_classes,
994
+ step=1,
995
+ label="Min number of classes"
996
+ )
 
997
 
998
+ classes_max = gr.Slider(
999
+ min_classes, max_classes,
1000
+ value=max_classes,
1001
+ step=1,
1002
+ label="Max number of classes"
1003
+ )
1004
 
1005
+ with gr.Column():
1006
+ sep_min = gr.Slider(
1007
+ min_sep, max_sep,
1008
+ value=min_sep,
1009
+ step=0.01,
1010
+ label="Min class separation"
1011
+ )
1012
 
1013
+ sep_max = gr.Slider(
1014
+ min_sep, max_sep,
1015
+ value=max_sep,
1016
+ step=0.01,
1017
+ label="Max class separation"
1018
+ )
1019
+
1020
+ perf_table = gr.DataFrame(
1021
  interactive=False,
 
1022
  type="pandas",
1023
+ wrap=True,
1024
  )
1025
 
1026
+ count_md = gr.Markdown("")
1027
+
1028
+
1029
+ controls = [
1030
+ features_min, features_max,
1031
+ samples_min, samples_max,
1032
+ classes_min, classes_max,
1033
+ sep_min, sep_max,
1034
+ ]
1035
+
1036
+ for c in controls:
1037
+ c.change(
1038
+ fn=filter_and_aggregate,
1039
+ inputs=controls,
1040
+ outputs=[perf_table, count_md],
1041
+ )
1042
+
1043
+
1044
  # # Optional: visual comparison chart
1045
  # with gr.Accordion("📈 Visualize Differences", open=False):
1046
 
 
1076
  def show_content(visible_content, selected_btn):
1077
  # All content blocks and buttons
1078
  content_blocks = [home_intro, public_content, retail_domain_content, finance_domain_content, healthcare_domain_content, private_content, datamap_content]
1079
+ ## btns = [home_btn, public_btn, domain_retail_btn, domain_finance_btn, domain_healthcare_btn, private_btn, datamap_btn]
1080
+ btns = [public_btn_home, home_btn_public, home_btn_retail, home_btn_finance, home_btn_health, home_btn_private, home_btn_datamap]
1081
  # Set visibility
1082
  updates = {block: gr.update(visible=(block == visible_content)) for block in content_blocks}
1083
  # Set button classes
 
1089
  return updates
1090
 
1091
  def show_home():
1092
+ return show_content(home_intro, public_btn_home)
1093
 
1094
  def show_public():
1095
+ return show_content(public_content, home_btn_public)
1096
  def show_demain_retail():
1097
+ return show_content(retail_domain_content, home_btn_retail)
1098
  def show_domain_finance():
1099
+ return show_content(finance_domain_content, home_btn_finance)
1100
  def show_domain_healthcare():
1101
+ return show_content(healthcare_domain_content, home_btn_health)
1102
 
1103
  def show_private():
1104
+ return show_content(private_content, home_btn_private)
1105
 
1106
  def show_datamap():
1107
+ return show_content(datamap_content, home_btn_datamap)
1108
 
1109
 
1110
+ # outputs = [home_intro, public_content, retail_domain_content, finance_domain_content, healthcare_domain_content, private_content, datamap_content, home_btn, public_btn, domain_retail_btn, domain_finance_btn, domain_healthcare_btn, private_btn, datamap_btn]
1111
+ outputs = [home_intro, public_content, retail_domain_content, finance_domain_content, healthcare_domain_content, private_content, datamap_content, public_btn_home, home_btn_public, home_btn_retail, home_btn_finance, home_btn_health, home_btn_private, home_btn_datamap]
1112
+ # home_btn.click(fn=show_home, inputs=None, outputs=outputs)
1113
+ home_btn_retail.click(fn=show_home, inputs=None, outputs=outputs)
1114
+ home_btn_finance.click(fn=show_home, inputs=None, outputs=outputs)
1115
+ home_btn_health.click(fn=show_home, inputs=None, outputs=outputs)
1116
+ home_btn_public.click(fn=show_home, inputs=None, outputs=outputs)
1117
+ home_btn_private.click(fn=show_home, inputs=None, outputs=outputs)
1118
+ home_btn_datamap.click(fn=show_home, inputs=None, outputs=outputs)
1119
+
1120
 
1121
+ # public_btn.click(fn=show_public, inputs=None, outputs=outputs)
1122
+ # domain_retail_btn.click(fn=show_demain_retail, inputs=None, outputs=outputs)
1123
+ # domain_finance_btn.click(fn=show_domain_finance, inputs=None, outputs=outputs)
1124
+ # domain_healthcare_btn.click(fn=show_domain_healthcare, inputs=None, outputs=outputs)
1125
 
1126
+ # private_btn.click(fn=show_private, inputs=None, outputs=outputs)
1127
+
1128
+ # datamap_btn.click(fn=show_datamap, inputs=None, outputs=outputs)
1129
+
1130
+ public_btn_home.click(fn=show_public, inputs=None, outputs=outputs)
1131
+ private_btn_home.click(fn=show_private, inputs=None, outputs=outputs)
1132
+ datamap_btn_home.click(fn=show_datamap, inputs=None, outputs=outputs)
1133
 
1134
+ finance_btn_home.click(fn=show_domain_finance, inputs=None, outputs=outputs)
1135
+ healthcare_btn_home.click(fn=show_domain_healthcare, inputs=None, outputs=outputs)
1136
+ retail_btn_home.click(fn=show_demain_retail, inputs=None, outputs=outputs)
1137
 
1138
+ demo.launch(ssr_mode=False, share=False)
complete_results_acad.json ADDED
The diff for this file is too large to render. See raw diff
 
complete_results_indus.json ADDED
The diff for this file is too large to render. See raw diff
 
complete_results_indus_noxgboost.json ADDED
The diff for this file is too large to render. See raw diff
 
workflow.png → make_classif-parameter_space.parquet RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:10b4e35313af20b830b513ff4e79dbabe781d2a73452b5f6962604a1082b1b6d
3
- size 429650
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0959a1f1204634a61bbc732fdeac0f1397755f1daadcd9e72b869f3c58cf4d99
3
+ size 5623086
model_info.json CHANGED
@@ -1,56 +1,61 @@
1
  [
2
  {
3
- "model_name": "NICL",
4
  "model_type": "Tabular Foundation Model",
5
  "model_description": "Our in-house tabular foundation model based on an in-context learning architecture."
6
  },
7
  {
8
- "model_name": "Random Forest",
9
  "model_type": "Decision Trees",
10
- "model_description": "A robust ensemble method that builds multiple decision trees and averages their predictions to reduce overfitting and improve accuracy."
11
  },
12
  {
13
- "model_name": "MLP",
14
- "model_type": "Neural Networks",
15
- "model_description": "A Neural Networks that models tabular data by learning non-linear interactions between numerical and embedded categorical features."
16
  },
17
  {
18
- "model_name": "XGBoost",
19
  "model_type": "Decision Trees",
20
- "model_description": "A highly efficient and scalable gradient boosting framework that improves performance with regularization and handles large tabular datasets effectively."
21
  },
22
  {
23
- "model_name": "CatBoost",
24
  "model_type": "Decision Trees",
25
- "model_description": "A high-performance gradient boosting algorithm that handles categorical features natively and requires minimal preprocessing."
26
  },
27
  {
28
- "model_name": "ModernNCA",
29
  "model_type": "Neural Networks",
30
  "model_description": "An advanced extension of Neighborhood Component Analysis (NCA) that employs deep neural networks with stochastic neighborhood sampling to learn complex feature interactions for tabular data."
31
  },
32
  {
33
- "model_name": "TabPFNv2",
34
  "model_type": "Tabular Foundation Model",
35
  "model_description": "A transformer-based model that performs in-context learning by approximating Bayesian inference for tabular classification on small datasets."
36
  },
37
  {
38
- "model_name": "RealMLP",
39
- "model_type": "Multilayer Perceptron",
40
- "model_description": "An enhanced MLP optimized with strong default parameters, achieving competitive performance on tabular data."
41
  },
42
  {
43
- "model_name": "TabICL",
44
  "model_type": "Tabular Foundation Model",
45
  "model_description": "A transformer-based model that performs feature compression before doing in-context learning on tabular data by conditioning on labeled support examples to predict unseen queries without task-specific training."
46
  },
47
  {
48
- "model_name": "LightGBM",
49
  "model_type": "Decision Trees",
50
  "model_description": "A fast gradient boosting framework that builds decision trees using histogram-based learning for scalable, high-performance tabular modeling."
51
  },
52
  {
53
- "model_name": "TabM",
 
 
 
 
 
54
  "model_type": "Neural Networks",
55
  "model_description": "A deep learning model that efficiently imitates an Neural Networks, enhancing performance on tabular data tasks without the overhead of training multiple models."
56
  }
 
1
  [
2
  {
3
+ "model_name": "nicl",
4
  "model_type": "Tabular Foundation Model",
5
  "model_description": "Our in-house tabular foundation model based on an in-context learning architecture."
6
  },
7
  {
8
+ "model_name": "xgboost",
9
  "model_type": "Decision Trees",
10
+ "model_description": "A highly efficient and scalable gradient boosting framework that improves performance with regularization and handles large tabular datasets effectively."
11
  },
12
  {
13
+ "model_name": "xgboost_ensemble",
14
+ "model_type": "Decision Trees",
15
+ "model_description": "(Ensembled Version) A highly efficient and scalable gradient boosting framework that improves performance with regularization and handles large tabular datasets effectively."
16
  },
17
  {
18
+ "model_name": "catboost",
19
  "model_type": "Decision Trees",
20
+ "model_description": "A high-performance gradient boosting algorithm that handles categorical features natively and requires minimal preprocessing."
21
  },
22
  {
23
+ "model_name": "catboost_ensemble",
24
  "model_type": "Decision Trees",
25
+ "model_description": "(Ensembled Version) A high-performance gradient boosting algorithm that handles categorical features natively and requires minimal preprocessing."
26
  },
27
  {
28
+ "model_name": "modern-nca",
29
  "model_type": "Neural Networks",
30
  "model_description": "An advanced extension of Neighborhood Component Analysis (NCA) that employs deep neural networks with stochastic neighborhood sampling to learn complex feature interactions for tabular data."
31
  },
32
  {
33
+ "model_name": "tabpfn2.5",
34
  "model_type": "Tabular Foundation Model",
35
  "model_description": "A transformer-based model that performs in-context learning by approximating Bayesian inference for tabular classification on small datasets."
36
  },
37
  {
38
+ "model_name": "realmlp",
39
+ "model_type": "Neural Networks",
40
+ "model_description": "An enhanced MLP optimized with strong default parameters, achieving competitive performance on tabular data. Note that due to computate limitation, we used the simple version of realmlp."
41
  },
42
  {
43
+ "model_name": "tabicl",
44
  "model_type": "Tabular Foundation Model",
45
  "model_description": "A transformer-based model that performs feature compression before doing in-context learning on tabular data by conditioning on labeled support examples to predict unseen queries without task-specific training."
46
  },
47
  {
48
+ "model_name": "lightgbm",
49
  "model_type": "Decision Trees",
50
  "model_description": "A fast gradient boosting framework that builds decision trees using histogram-based learning for scalable, high-performance tabular modeling."
51
  },
52
  {
53
+ "model_name": "lightgbm_ensemble",
54
+ "model_type": "Decision Trees",
55
+ "model_description": "(Ensembled Version) A fast gradient boosting framework that builds decision trees using histogram-based learning for scalable, high-performance tabular modeling."
56
+ },
57
+ {
58
+ "model_name": "tabm",
59
  "model_type": "Neural Networks",
60
  "model_description": "A deep learning model that efficiently imitates an Neural Networks, enhancing performance on tabular data tasks without the overhead of training multiple models."
61
  }
private_dummy.json DELETED
The diff for this file is too large to render. See raw diff
 
public_datasets_info.json CHANGED
The diff for this file is too large to render. See raw diff
 
public_dummy.json DELETED
The diff for this file is too large to render. See raw diff
 
public_dummy_first.json DELETED
The diff for this file is too large to render. See raw diff
 
qrt.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "tabpfn2.5" : 50.72,
3
+ "lightgbm" : 50.98,
4
+ "xgboost" : 51.18,
5
+ "tabicl" : 51.58,
6
+ "nicl" : 51.70
7
+ }
requirements.txt CHANGED
@@ -12,3 +12,5 @@ seaborn
12
  scikit-learn
13
 
14
  requests
 
 
 
12
  scikit-learn
13
 
14
  requests
15
+
16
+ pyarrow
run.py CHANGED
@@ -2,7 +2,7 @@ import pandas as pd
2
  import json
3
 
4
  # Load model performance per dataset
5
- with open("public_dummy.json", "r") as f:
6
  public_per_dataset = pd.json_normalize(json.load(f))
7
 
8
  # Load dataset metadata (including industries)
 
2
  import json
3
 
4
  # Load model performance per dataset
5
+ with open("complete_results_acad.json", "r") as f:
6
  public_per_dataset = pd.json_normalize(json.load(f))
7
 
8
  # Load dataset metadata (including industries)