diff --git a/docs/guide/bandits.ipynb b/docs/guide/bandits.ipynb
index 2859a007..71ce6f12 100644
--- a/docs/guide/bandits.ipynb
+++ b/docs/guide/bandits.ipynb
@@ -17,7 +17,7 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
@@ -43,7 +43,7 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 3,
"metadata": {},
"outputs": [
{
@@ -191,7 +191,7 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
@@ -210,7 +210,7 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 5,
"metadata": {},
"outputs": [
{
@@ -218,9 +218,8 @@
"output_type": "stream",
"text": [
"Completed 100% [====================]\n",
- "Saved population to file /tmp/tmpshx7uzc1/population.json\n",
"saving final population as archive...\n",
- "score: 0.8900709673753779\n"
+ "score: 0.8972961714305525\n"
]
}
],
@@ -239,7 +238,7 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 6,
"metadata": {},
"outputs": [
{
@@ -287,7 +286,7 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 7,
"metadata": {},
"outputs": [
{
@@ -297,7 +296,7 @@
"Search Space\n",
"===\n",
"terminal_map: {\"ArrayB\": [\"1.00\"], \"ArrayI\": [\"x5\", \"x7\", \"1.00\"], \"ArrayF\": [\"x0\", \"x1\", \"x2\", \"x3\", \"x4\", \"x6\", \"1.00\", \"1.00*MeanLabel\"]}\n",
- "terminal_weights: {\"ArrayB\": [-nan], \"ArrayI\": [0.5, 0.5, 0.5], \"ArrayF\": [0.5302013, 0.5300546, 0.55172414, 0.55825245, 0.5, 0.55445546, 0.407767, 0.3604651]}\n",
+ "terminal_weights: {\"ArrayB\": [-nan], \"ArrayI\": [0.5, 0.5, 0.5], \"ArrayF\": [0.31623933, 0.37096775, 0.28431374, 0.3359375, 0.36923078, 0.3006993, 0.5485714, 0.5503876]}\n",
"node_map[ArrayI][[\"ArrayI\", \"ArrayI\"]][SplitBest] = SplitBest, weight = 1\n",
"node_map[MatrixF][[\"ArrayF\", \"ArrayF\", \"ArrayF\", \"ArrayF\"]][Logabs] = Logabs, weight = 1\n",
"node_map[MatrixF][[\"ArrayF\", \"ArrayF\", \"ArrayF\", \"ArrayF\"]][Exp] = Exp, weight = 1\n",
@@ -335,7 +334,7 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 8,
"metadata": {},
"outputs": [
{
@@ -354,15 +353,15 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "0.19159255921840668\n",
- "{'delete': 0.3327217102050781, 'insert': 0.014492753893136978, 'point': 0.47653430700302124, 'subtree': 0.687393069267273, 'toggle_weight_off': 0.40665435791015625, 'toggle_weight_on': 0.019417475908994675}\n"
+ "0.1598760038614273\n",
+ "{'delete': 0.272018700838089, 'insert': 0.019999999552965164, 'point': 0.38034459948539734, 'subtree': 0.6300863027572632, 'toggle_weight_off': 0.5979797840118408, 'toggle_weight_on': 0.036269430071115494}\n"
]
}
],
@@ -388,7 +387,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.1.undefined"
+ "version": "3.12.2"
}
},
"nbformat": 4,
diff --git a/docs/guide/search_space.ipynb b/docs/guide/search_space.ipynb
index 2f01433e..25bde8e4 100644
--- a/docs/guide/search_space.ipynb
+++ b/docs/guide/search_space.ipynb
@@ -29,18 +29,133 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 11,
"id": "b667948a",
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " id | \n",
+ " sex | \n",
+ " race | \n",
+ " target | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " count | \n",
+ " 993.00000 | \n",
+ " 993.000000 | \n",
+ " 993.000000 | \n",
+ " 993.000000 | \n",
+ "
\n",
+ " \n",
+ " mean | \n",
+ " 496.00000 | \n",
+ " 0.487412 | \n",
+ " 2.625378 | \n",
+ " 8.219092 | \n",
+ "
\n",
+ " \n",
+ " std | \n",
+ " 286.79871 | \n",
+ " 0.500093 | \n",
+ " 1.725240 | \n",
+ " 1.101319 | \n",
+ "
\n",
+ " \n",
+ " min | \n",
+ " 0.00000 | \n",
+ " 0.000000 | \n",
+ " 0.000000 | \n",
+ " 1.337280 | \n",
+ "
\n",
+ " \n",
+ " 25% | \n",
+ " 248.00000 | \n",
+ " 0.000000 | \n",
+ " 1.000000 | \n",
+ " 7.836757 | \n",
+ "
\n",
+ " \n",
+ " 50% | \n",
+ " 496.00000 | \n",
+ " 0.000000 | \n",
+ " 3.000000 | \n",
+ " 8.404038 | \n",
+ "
\n",
+ " \n",
+ " 75% | \n",
+ " 744.00000 | \n",
+ " 1.000000 | \n",
+ " 4.000000 | \n",
+ " 8.810710 | \n",
+ "
\n",
+ " \n",
+ " max | \n",
+ " 992.00000 | \n",
+ " 1.000000 | \n",
+ " 5.000000 | \n",
+ " 11.410597 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " id sex race target\n",
+ "count 993.00000 993.000000 993.000000 993.000000\n",
+ "mean 496.00000 0.487412 2.625378 8.219092\n",
+ "std 286.79871 0.500093 1.725240 1.101319\n",
+ "min 0.00000 0.000000 0.000000 1.337280\n",
+ "25% 248.00000 0.000000 1.000000 7.836757\n",
+ "50% 496.00000 0.000000 3.000000 8.404038\n",
+ "75% 744.00000 1.000000 4.000000 8.810710\n",
+ "max 992.00000 1.000000 5.000000 11.410597"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"import pandas as pd\n",
"from pybrush import Dataset, SearchSpace\n",
"\n",
- "df = pd.read_csv('../examples/datasets/d_enc.csv')\n",
- "X = df.drop(columns='label')\n",
- "y = df['label']\n",
+ "df = pd.read_csv('../examples/datasets/d_example_patients.csv')\n",
+ "X = df.drop(columns='target')\n",
+ "y = df['target']\n",
"\n",
+ "df.describe()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "6d563aae",
+ "metadata": {},
+ "outputs": [],
+ "source": [
"data = Dataset(X,y)\n",
"\n",
"search_space = SearchSpace(data)"
@@ -59,7 +174,7 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 14,
"id": "23d6f552",
"metadata": {},
"outputs": [],
@@ -93,7 +208,7 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 15,
"id": "a2953719",
"metadata": {},
"outputs": [
@@ -101,17 +216,17 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Search Space\n",
- "===\n",
- "terminal_map: {\"ArrayB\": [\"1.00\"], \"ArrayI\": [\"x_5\", \"x_7\", \"1.00\"], \"ArrayF\": [\"x_0\", \"x_1\", \"x_2\", \"x_3\", \"x_4\", \"x_6\", \"1.00\", \"1.00*MeanLabel\"]}\n",
- "terminal_weights: {\"ArrayB\": [-nan], \"ArrayI\": [0.011619061, 0.03579926, 0.023709161], \"ArrayF\": [0.6343385, 0.67299956, 0.42711574, 0.8625447, 0.8957853, 0.20750472, 0.6167148, 0.6167148]}\n",
+ "=== Search space ===\n",
+ "terminal_map: {\"ArrayI\": [\"x_2\", \"1.00\"], \"ArrayB\": [\"x_1\", \"1.00\"], \"ArrayF\": [\"x_0\", \"1.00\", \"1.00*MeanLabel\"]}\n",
+ "terminal_weights: {\"ArrayI\": [0.01214596, 0.01214596], \"ArrayB\": [0.026419641, 0.026419641], \"ArrayF\": [0.056145623, 0.056145623, 0.056145623]}\n",
+ "node_map[ArrayB][[\"ArrayB\", \"ArrayB\"]][SplitBest] = SplitBest, weight = 0.2\n",
"node_map[ArrayI][[\"ArrayI\", \"ArrayI\"]][SplitBest] = SplitBest, weight = 0.2\n",
"node_map[ArrayF][[\"ArrayF\", \"ArrayF\"]][SplitBest] = SplitBest, weight = 0.2\n",
"node_map[ArrayF][[\"ArrayF\", \"ArrayF\"]][Div] = Div, weight = 0.1\n",
"node_map[ArrayF][[\"ArrayF\", \"ArrayF\"]][Mul] = Mul, weight = 1\n",
"node_map[ArrayF][[\"ArrayF\", \"ArrayF\"]][Sub] = Sub, weight = 0.5\n",
"node_map[ArrayF][[\"ArrayF\", \"ArrayF\"]][Add] = Add, weight = 0.5\n",
- "===\n"
+ "\n"
]
}
],
@@ -129,6 +244,48 @@
"Note also that the default behavior is to give both of these nodes the same weight as specified by the user. "
]
},
+ {
+ "cell_type": "markdown",
+ "id": "ca903d90",
+ "metadata": {},
+ "source": [
+ "## Loading datatypes\n",
+ "\n",
+ "If you pass a numpy array, Brush will try to infer datatypes based on its values.\n",
+ "If instead of passing the data directly you rather pass a pandas dataframe, then it will use the data types retrieved from the powerful pandas sniffer to use as its own data type."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "id": "1c8c72c1",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "=== Search space ===\n",
+ "terminal_map: {\"ArrayI\": [\"x_2\", \"1.00\"], \"ArrayB\": [\"x_1\", \"1.00\"], \"ArrayF\": [\"x_0\", \"1.00\", \"1.00*MeanLabel\"]}\n",
+ "terminal_weights: {\"ArrayI\": [0.01214596, 0.01214596], \"ArrayB\": [0.026419641, 0.026419641], \"ArrayF\": [0.056145623, 0.056145623, 0.056145623]}\n",
+ "node_map[ArrayB][[\"ArrayB\", \"ArrayB\"]][SplitBest] = SplitBest, weight = 0.2\n",
+ "node_map[ArrayI][[\"ArrayI\", \"ArrayI\"]][SplitBest] = SplitBest, weight = 0.2\n",
+ "node_map[ArrayF][[\"ArrayF\", \"ArrayF\"]][SplitBest] = SplitBest, weight = 0.2\n",
+ "node_map[ArrayF][[\"ArrayF\", \"ArrayF\"]][Div] = Div, weight = 0.1\n",
+ "node_map[ArrayF][[\"ArrayF\", \"ArrayF\"]][Mul] = Mul, weight = 1\n",
+ "node_map[ArrayF][[\"ArrayF\", \"ArrayF\"]][Sub] = Sub, weight = 0.5\n",
+ "node_map[ArrayF][[\"ArrayF\", \"ArrayF\"]][Add] = Add, weight = 0.5\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "data = Dataset(X.values, y.values)\n",
+ "\n",
+ "search_space = SearchSpace(data, user_ops)\n",
+ "search_space.print()"
+ ]
+ },
{
"cell_type": "markdown",
"id": "d662c5a7",
diff --git a/src/bandit/thompson.cpp b/src/bandit/thompson.cpp
index 93214012..f297c5e9 100644
--- a/src/bandit/thompson.cpp
+++ b/src/bandit/thompson.cpp
@@ -26,11 +26,39 @@ ThompsonSamplingBandit::ThompsonSamplingBandit(map arms_probs)
template
std::map ThompsonSamplingBandit::sample_probs(bool update) {
+
+ // from https://stackoverflow.com/questions/4181403/generate-random-number-based-on-beta-distribution-using-boost
+ // You'll first want to draw a random number uniformly from the
+ // range (0,1). Given any distribution, you can then plug that number
+ // into the distribution's "quantile function," and the result is as
+ // if a random value was drawn from the distribution.
+ // from https://stackoverflow.com/questions/10358064/random-numbers-from-beta-distribution-c
+ // The beta distribution is related to the gamma distribution. Let X be a
+ // random number drawn from Gamma(α,1) and Y from Gamma(β,1), where the
+ // first argument to the gamma distribution is the shape parameter.
+ // Then Z=X/(X+Y) has distribution Beta(α,β).
+
if (update) {
+ // 1. use a beta distribution based on alphas and betas to sample probabilities
+ // 2. normalize probabilities so the sum is 1?
+
+ float alpha, beta, X, Y, prob;
for (const auto& pair : this->probabilities) {
T arm = pair.first;
- float prob = static_cast(alphas[arm] - 1) / static_cast(alphas[arm] + betas[arm] - 2);
+
+ alpha = alphas[arm];
+ beta = betas[arm];
+
+ // TODO: stop using boost and use std::gamma_distribution (first, search to see if it is faster)
+ boost::math::gamma_distribution<> gammaX(alpha);
+ boost::math::gamma_distribution<> gammaY(beta);
+
+ X = boost::math::quantile(gammaX, Brush::Util::r.rnd_flt());
+ Y = boost::math::quantile(gammaY, Brush::Util::r.rnd_flt());
+
+ prob = X/(X+Y);
+
this->probabilities[arm] = prob;
}
}
diff --git a/src/bandit/thompson.h b/src/bandit/thompson.h
index c6ab3dda..f12fa2e1 100644
--- a/src/bandit/thompson.h
+++ b/src/bandit/thompson.h
@@ -1,7 +1,14 @@
#include "bandit_operator.h"
-// https://www.boost.org/doc/libs/1_85_0/doc/html/boost/random/beta_distribution.html
-#include
+// #include
+// #include
+
+#include
+
+// // https://www.boost.org/doc/libs/1_85_0/doc/html/boost/random/beta_distribution.html
+// #include
+
+#include "../util/utils.h" // to use random generator
#ifndef THOMPSON_H
#define THOMPSON_H
@@ -9,9 +16,6 @@
namespace Brush {
namespace MAB {
-// TODO: rename thompson to proportional. implement thompson in other file
-using namespace boost::random;
-
template
class ThompsonSamplingBandit : public BanditOperator
{
@@ -25,7 +29,6 @@ class ThompsonSamplingBandit : public BanditOperator
private:
// additional stuff should come here
- beta_distribution<> BetaDistribution;
std::map alphas;
std::map betas;
diff --git a/tests/cpp/test_bandit.cpp b/tests/cpp/test_bandit.cpp
index 54ba4bc2..ff9e0863 100644
--- a/tests/cpp/test_bandit.cpp
+++ b/tests/cpp/test_bandit.cpp
@@ -60,7 +60,6 @@ TEST_P(BanditTest, BanditProbabilities) {
// things dont change
std::map sampledProbs = bandit.sample_probs(true);
- EXPECT_EQ(sampledProbs, initialProbs);
// Update the bandit with arm 1 and reward 1.0
bandit.update("foo1", 1.0);