AI Center of Excellence at Fidelity Investments

Mab2Rec:
Multi-Armed Bandit Recommenders

Bandit-based recommender systems for enterprise applications with context-free, parametric, and non-parametric contextual policies. Designed for modularity, rapid experimentation, and rigorous evaluation.

Serdar Kadıoğlu1,2   Bernard Kleynhans2   Xin Wang2

1 Department of Computer Science, Brown University 2 AI Center of Excellence, Fidelity Investments

Code API Docs Notebooks Tutorial Presentation AI Magazine'25 AAAI'24
Installpip install mab2rec
Mab2Rec downloads
# Example of how to train a single recommender to generate top-4 recommendations

# Import
from mab2rec import BanditRecommender, LearningPolicy
from mab2rec.pipeline import train, score

# LinGreedy recommender to select top-4 items with 10% random exploration
rec = BanditRecommender(LearningPolicy.LinGreedy(epsilon=0.1), top_k=4)

# Train on (user, item, response) interactions in train data using user features
train(rec, data='data/data_train.csv',
      user_features='data/features_user.csv')

# Score recommendations for users in test data. The output df holds
# user_id, item_id, score columns for every test user for top-k items
df = score(rec, data='data/data_test.csv',
           user_features='data/features_user.csv')
@inproceedings{mab2rec,
  title={Building higher-order abstractions from the components of recommender systems},
  author={Kad{\i}o{\u{g}}lu, Serdar and Kleynhans, Bernard},
  booktitle={Proceedings of the AAAI Conference on Artificial Intelligence},
  volume={38},
  number={21},
  pages={22998--23004},
  year={2024}
}
@article{kadiouglu2025open,
  title={Open-source AI at scale: Establishing an enterprise AI strategy through modular frameworks},
  author={Kad{\i}o{\u{g}}lu, Serdar},
  journal={AI Magazine},
  volume={46},
  number={3},
  pages={e70032},
  year={2025},
  publisher={Wiley Online Library}
}

Overview

Mab2Rec is a Python framework for building bandit-based recommendation systems for enterprise applications. It is designed to enable a modular, interoperable, and scalable AI ecosystem for recommender systems, built on robust and reusable open-source components.


Modular Architecture

Mab2Rec composes specialized open-source components for recommendation, representation learning, fairness and performance evaluation.

Bandit Policies

MABWiser

Core engine to create multi-armed bandit recommendation algorithms used by Mab2Rec.

pip install mabwiser
# An example that shows how to use the UCB1 learning policy
# to choose between two arms based on their expected rewards.

# Import MABWiser Library
from mabwiser.mab import MAB, LearningPolicy, NeighborhoodPolicy

# Data
arms = ['Arm1', 'Arm2']
decisions = ['Arm1', 'Arm1', 'Arm2', 'Arm1']
rewards = [20, 17, 25, 9]

# Model
mab = MAB(arms, LearningPolicy.UCB1(alpha=1.25))

# Train
mab.fit(decisions, rewards)

# Test
mab.predict()
@article{mabwiser,
  title={MABWiser: parallelizable contextual multi-armed bandits},
  author={Strong, Emily and Kleynhans, Bernard and Kad{\i}{\u{g}}lu, Serdar},
  journal={International Journal on Artificial Intelligence Tools},
  volume={30},
  number={04},
  pages={2150021},
  year={2021},
  publisher={World Scientific}
}
MABWiser downloads

Bernard Kleynhands, Emily Strong, Xin Wang, Serdar Kadıoğlu

Item Features

TextWiser

Text featurization toolkit to create item representations for recommender models.

pip install textwiser
# Conceptually, TextWiser is composed of an Embedding, potentially with a pretrained model,
# that can be chained into zero or more Transformations
from textwiser import TextWiser, Embedding, Transformation, WordOptions, PoolOptions

# Data
documents = ["Some document", "More documents. Including multi-sentence documents."]

# Model: TFIDF `min_df` parameter gets passed to sklearn automatically
emb = TextWiser(Embedding.TfIdf(min_df=1))

# Model: TFIDF followed with an NMF + SVD
emb = TextWiser(Embedding.TfIdf(min_df=1), [Transformation.NMF(n_components=30), Transformation.SVD(n_components=10)])

# Model: Word2Vec with no pretraining that learns from the input data
emb = TextWiser(Embedding.Word(word_option=WordOptions.word2vec, pretrained=None), Transformation.Pool(pool_option=PoolOptions.min))

# Model: BERT with the pretrained bert-base-uncased embedding
emb = TextWiser(Embedding.Word(word_option=WordOptions.bert), Transformation.Pool(pool_option=PoolOptions.first))

# Features
vecs = emb.fit_transform(documents)
@inproceedings{textwiser,
  title={Representing the unification of text featurization using a context-free grammar},
  author={Kilit{\c{c}}ioglu, Doruk and Kad{\i}{\u{g}}lu, Serdar},
  booktitle={Proceedings of the AAAI Conference on Artificial Intelligence},
  volume={35},
  number={17},
  pages={15439--15445},
  year={2021}
}
TextWiser downloads

Karthik Uppuluri, Doruk Kilitçioğlu, Serdar Kadıoğlu

User Features

Selective

Feature selection toolkit to create user representations from structured and high-dimensional data.


pip install selective
# Import Selective and SelectionMethod
from sklearn.datasets import fetch_california_housing
from feature.utils import get_data_label
from feature.selector import Selective, SelectionMethod

# Data
data, label = get_data_label(fetch_california_housing())

# Feature selectors from simple to more complex
selector = Selective(SelectionMethod.Variance(threshold=0.0))
selector = Selective(SelectionMethod.Correlation(threshold=0.5, method="pearson"))
selector = Selective(SelectionMethod.Statistical(num_features=3, method="anova"))
selector = Selective(SelectionMethod.Linear(num_features=3, regularization="none"))
selector = Selective(SelectionMethod.TreeBased(num_features=3))

# Feature reduction
subset = selector.fit_transform(data, label)
print("Reduction:", list(subset.columns))
print("Scores:", list(selector.get_absolute_scores()))
@article{selective,
  title={Integrating optimized item selection with active learning for continuous exploration in recommender systems},
  author={Kad{\i}{\u{g}}lu, Serdar and Kleynhans, Bernard and Wang, Xin},
  journal={Annals of Mathematics and Artificial Intelligence},
  volume={92},
  number={6},
  pages={1585--1607},
  year={2024},
  publisher={Springer}
}
Selective downloads

Xin Wang, Bernard Kleynhans, Serdar Kadıoğlu

Sequential Pattern Mining

Seq2Pat

Sequential pattern mining toolkit to construct user representations from temporal interaction sequences.

pip install seq2pat
# Example to show how to find frequent sequential patterns
# from a given sequence database subject to constraints
from sequential.seq2pat import Seq2Pat, Attribute

# Seq2Pat over 3 sequences
seq2pat = Seq2Pat(sequences=[["A", "A", "B", "A", "D"],
                             ["C", "B", "A"],
                             ["C", "A", "C", "D"]])

# Price attribute corresponding to each item
price = Attribute(values=[[5, 5, 3, 8, 2],
                          [1, 3, 3],
                          [4, 5, 2, 1]])

# Average price constraint
seq2pat.add_constraint(3 <= price.average() <= 4)

# Patterns that occur at least twice (A-D)
patterns = seq2pat.get_patterns(min_frequency=2)
@article{seq2pat,
  title={Seq2Pat: Sequence-to-pattern generation to bridge pattern mining with machine learning},
  author={Kad{\i}{\u{g}}lu, Serdar and Wang, Xin and Hosseininasab, Amin and van Hoeve, Willem-Jan},
  journal={AI Magazine},
  volume={44},
  number={1},
  pages={54--66},
  year={2023},
  publisher={Wiley Online Library}
}
Seq2Pat downloads

Xin Wang, Amin Hosseininasab, Willem-Jan van Hoeve, Serdar Kadıoğlu

Fairness, Bias & Performance Evaluation

Jurity

Evaluation library for recommendation quality, including ranking, classification, and fairness metrics.

pip install jurity
# Import binary and multi-class fairness metrics
from jurity.fairness import BinaryFairnessMetrics, MultiClassFairnessMetrics

# Data
binary_predictions = [1, 1, 0, 1, 0, 0]
multi_class_predictions = ["a", "b", "c", "b", "a", "a"]
multi_class_multi_label_predictions = [["a", "b"], ["b", "c"], ["b"], ["a", "b"], ["c", "a"], ["c"]]
memberships = [0, 0, 0, 1, 1, 1]
classes = ["a", "b", "c"]

# Metrics (see also other available metrics)
metric = BinaryFairnessMetrics.StatisticalParity()
multi_metric = MultiClassFairnessMetrics.StatisticalParity(classes)

# Scores
print("Metric:", metric.description)
print("Lower Bound: ", metric.lower_bound)
print("Upper Bound: ", metric.upper_bound)
print("Ideal Value: ", metric.ideal_value)
print("Binary Fairness score: ", metric.get_score(binary_predictions, memberships))
print("Multi-class Fairness scores: ", multi_metric.get_scores(multi_class_predictions, memberships))
print("Multi-class multi-label Fairness scores: ", multi_metric.get_scores(multi_class_multi_label_predictions, memberships))
@article{jurity,
  title={Surrogate Modeling to Address the Absence of Protected Membership Attributes in Fairness Evaluation},
  author={Kadio{\u{g}}lu, Serdar and Thielbar, Melinda},
  journal={ACM Transactions on Evolutionary Learning},
  volume={5},
  number={3},
  pages={1--25},
  year={2025},
  publisher={ACM New York, NY}
}
Jurity downloads

Filip Michalsky, Melinda Thielbar, Serdar Kadıoğlu

Explainable AI

BoolXAI

Explainable AI based on expressive Boolean formulas.

pip install boolxai
import numpy as np
from sklearn.metrics import balanced_accuracy_score

from boolxai import BoolXAI, Operator

# Create random toy data for binary classification. X and y must be binary!
rng = np.random.default_rng(seed=42)
X = rng.choice([0, 1], size=(100, 10))
y = rng.choice([0, 1], size=100)

# Rule classifier with maximum depth, complexity, possible operators
rule_classifier = BoolXAI.RuleClassifier(max_depth=3,
                                         max_complexity=6,
                                         operators=[Operator.And, Operator.Or, Operator.Choose, Operator.AtMost, Operator.AtLeast],
                                         random_state=42)

# Learn the best rule
rule_classifier.fit(X, y)

# Best rule and best score
best_rule = rule_classifier.best_rule_
best_score = rule_classifier.best_score_
print(f"{best_rule=} {best_score=:.2f}")

# The depth of a rule is the number of edges in the longest path from the root to any leaf/literal.
# The complexity of a rule is the total number of operators and literals.
print(f"depth={best_rule.depth()} complexity={best_rule.complexity()}")

# Predict and score
y_pred = rule_classifier.predict(X)
score = balanced_accuracy_score(y, y_pred)
print(f"{score=:.2f}")

# It is also possible to plot the best rule --requires installing plot dependencies
best_rule.plot()

# or get a networkx.DiGraph representation of the rule --requires installing plot dependencies
G = best_rule.to_graph()
print(G)
@inproceedings{boolxai,
  title={BoolXAI: Explainable AI Using Expressive Boolean Formulas},
  author={Kad{\i}{\u{g}}lu, Serdar and Zhu, Elton Yechao and Rosenberg, Gili and Brubaker, John Kyle and Schuetz, Martin JA and Salton, Grant and Zhu, Zhihuai and Katzgraber, Helmut G},
  booktitle={Proceedings of the AAAI Conference on Artificial Intelligence},
  volume={39},
  number={28},
  pages={28900--28906},
  year={2025}
}
BoolXAI downloads

Serdar Kadıoğlu, Elton Zhu, Gili Rosenberg, Martin Schuetz


Industry-Strength Open-Source Software


Patents

Selected patents across recommender systems, fairness, optimization, predictive modeling, and reinforcement learning.

Cross-system recommender Evaluating probabilistic fairness of machine learning classification models Automatic data-driven optimization of a target outcome using machine learning Constraint-based predictive machine learning Determining future user actions using time-based featurization of clickstream data Surrogate ground truth generation in AI-based marketing campaigns Digital content classification and recommendation based on AI reinforcement learning Automated predictive product recommendations using reinforcement learning

Resources

Talks, tutorials, community resources, and practical references for building recommender systems.

NVIDIA Keynote Enterprise AI at Amherst College Invited Lecture at Bucknell University Comet ML Hyper-Personalization ACM RecSys Official Frameworks Mab2Rec Tutorial at ODSC Business Impact with Open-Source AI at NYC TechWeek Guest Lecture at University of Pennsylvania Invited Session at All Things Open Research Seminar at École Polytechnique Research Seminar at Université Côte d'Azur