"""Copyright 2015 Roger R Labbe Jr.
FilterPy library.
http://github.com/rlabbe/filterpy
Documentation at:
https://filterpy.readthedocs.org
Supporting book at:
https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python
This is licensed under an MIT license. See the readme.MD file
for more information.
"""
import numpy as np
from numpy.random import random
def residual_resample(weights):
""" Performs the residual resampling algorithm used by particle filters.
Based on observation that we don't need to use random numbers to select
most of the weights. Take int(N*w^i) samples of each particle i, and then
resample any remaining using a standard resampling algorithm [1]
**Parameters**
weights : list-like of float
list of weights as floats
**Returns**
indexes : ndarray of ints
array of indexes into the weights defining the resample. i.e. the
index of the zeroth resample is indexes[0], etc.
**References**
.. [1] J. S. Liu and R. Chen. Sequential Monte Carlo methods for dynamic
systems. Journal of the American Statistical Association,
93(443):1032–1044, 1998.
"""
N = len(weights)
indexes = np.zeros(N, 'i')
num_copies = (np.floor(N*np.asarray(weights))).astype(int)
k = 0
for i in range(N):
for _ in range(num_copies[i]):
indexes[k] = i
k += 1
residual = weights - num_copies
residual /= sum(residual)
cumulative_sum = np.cumsum(residual)
cumulative_sum[-1] = 1.
indexes[k:N] = np.searchsorted(cumulative_sum, random(N-k))
return indexes
def stratified_resample(weights):
N = len(weights)
positions = (random(N) + range(N)) / N
indexes = np.zeros(N, 'i')
cumulative_sum = np.cumsum(weights)
i, j = 0, 0
while i < N:
if positions[i] < cumulative_sum[j]:
indexes[i] = j
i += 1
else:
j += 1
return indexes
def systematic_resample(weights):
N = len(weights)
positions = (random() + np.arange(N)) / N
indexes = np.zeros(N, 'i')
cumulative_sum = np.cumsum(weights)
i, j = 0, 0
while i < N:
if positions[i] < cumulative_sum[j]:
indexes[i] = j
i += 1
else:
j += 1
return indexes
def multinomial_resample(weights):
""" This is the naive form of roulette sampling where we compute the
cumulative sum of the weights and then use binary search to select the
resampled point based on a uniformly distributed random number. Run time
is O(n log n).
**Parameters**
weights : list-like of float
list of weights as floats
**Returns**
indexes : ndarray of ints
array of indexes into the weights defining the resample. i.e. the
index of the zeroth resample is indexes[0], etc.
"""
cumulative_sum = np.cumsum(weights)
cumulative_sum[-1] = 1.
return np.searchsorted(cumulative_sum, random(len(weights)))
if __name__ == '__main__':
w = np.array([1.,2.,3.,2.,1.])
w = w / np.sum(w)
'''print(residual_resample(w))
import matplotlib as mpl
cmap = mpl.colors.ListedColormap([[0., .4, 1.],
[0., .8, 1.],
[1., .8, 0.],
[1., .4, 0.]]*5)
bounds = np.array([1., 2., 4, 7, 8]*3)
bounds /= sum(bounds)
a = np.cumsum(bounds)
fig = plt.figure(figsize=(8,3))
ax = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.BoundaryNorm(a, cmap.N)
bar = mpl.colorbar.ColorbarBase(ax, cmap=cmap,
norm=norm,
drawedges=False,
spacing='proportional',
orientation='horizontal')
bar.set_ticks([])
plt.show()'''