I have some code that randomly generates a number from m_min=10
to m_max=100
(apologies if this nomenclature is unconventional) for a total of (m_max - m_min) + 1 = 91 positions = n_positions
each with equal probability of being picked (i.e. a uniform distribution in the form of a probability vector).
I'm running a function using each number and receiving a score, if it's better than the previous score I want to update the weights for each position. Instead of discretely updating weights, I want to also update the weights of the neighboring positions for a smooth curve.
My thoughts for implementing was to do the following:
(1) update the weights for position_k
;
(2) fit curve to a beta-distribution
(this part gets tricky); and then
(3) when I draw another number from m_min
to m_max
, call it query_num
, I will divide that by n_positions
(i.e. total number of positions) to get my x
for the calculating the probability of drawing that value from the beta-distribution
.
I believe this is a bayesian
problem since I am using a uniform distribution as my prior and updating the posterior to get a beta-distribution
(if this is incorrect, please inform me).
I am clearly missing a fundamental step in the logic.
My ultimate goal is to "update" the posterior each time the condition == True
by adding mass to the regions around query_num
, recompute the probabilities based on a beta distribution
, and, in this case, plot the transformation.
I can't use a simple stats.beta.fit
because I don't have draws from the distribution only probabilities for of the x
values that I am updating.
import sys
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy import stats
from scipy.optimize import curve_fit
# Defaults
m_min = 10
m_max = 100
# Uniform probabilities
n_positions = m_max - m_min + 1
positions = np.arange(m_min, m_max + 1)
x = np.linspace(0,1,n_positions)
# Prior probabilities
probs_num = np.ones(n_positions)/n_positions # Each value is 0.01098901
# Placeholder function
def func(x):
# This isn't actually what I'm doing but just to get the code to work for this example
return 15 < x < 30
# Plot updates
n_iter = 100
update_value = 1e-3
with plt.style.context("seaborn-white"):
fig, ax = plt.subplots()
ax.plot(x, probs_num, label="Prior", color="black")
for i, color in enumerate(sns.color_palette(n_colors=n_iter)):
rs = np.random.RandomState(i)
# Get index of the position vector which is why I'm subtract `m_min`
query_num = rs.choice(positions, size=1, replace=False, p=probs_num)[0] - m_min
# Again the actual conidition is more complicated
condition = func(query_num)
# If it meets the criteria then update the "mass" in this area of the distribution
if condition:
probs_num[query_num] += update_value
# Normalize the values to probabilities again
probs_num = probs_num/probs_num.sum()
# Fit the curve to beta distribution (this is where it gets messed up)
params_fitted, _ = curve_fit(lambda x,a,b:stats.beta.pdf(x, a, b),
xdata=x,
ydata=probs_num,
)
ax.plot(x, stats.beta(*params_fitted).pdf(x), color=color, alpha=0.5, label=i)
legend_kws = {'bbox_to_anchor': (1, 0.5), 'edgecolor': 'black', 'facecolor': 'white', 'fontsize': 10, 'frameon': True, 'loc': 'center left'}
ax.legend(**legend_kws)
Versions:
Python v3.6.4, NumPy v1.14.2, SciPy v1.0.1