Dieser Code implementiert die Probennahme von n-d diskreten Wahrscheinlichkeitsverteilungen. Indem ein Flag auf das Objekt gesetzt wird, kann es auch als eine stückweise konstante Wahrscheinlichkeitsverteilung verwendet werden, die dann verwendet werden kann, um beliebige PDFs zu approximieren. Nun, beliebige PDFs mit kompakter Unterstützung; Wenn Sie extrem lange Tails effizient testen möchten, ist eine nicht einheitliche Beschreibung der PDF erforderlich. Aber auch für Dinge wie luftig-spreizende Funktionen (für die ich sie ursprünglich geschaffen habe) ist das immer noch effizient. Die interne Sortierung von Werten ist dort absolut kritisch, um Genauigkeit zu erhalten; die vielen kleinen Werte in den Schwänzen sollten wesentlich beitragen, aber sie werden in fp Genauigkeit ohne Sortierung übertönt werden. relevantes Beispiel
class Distribution(object):
"""
draws samples from a one dimensional probability distribution,
by means of inversion of a discrete inverstion of a cumulative density function
the pdf can be sorted first to prevent numerical error in the cumulative sum
this is set as default; for big density functions with high contrast,
it is absolutely necessary, and for small density functions,
the overhead is minimal
a call to this distibution object returns indices into density array
"""
def __init__(self, pdf, sort = True, interpolation = True, transform = lambda x: x):
self.shape = pdf.shape
self.pdf = pdf.ravel()
self.sort = sort
self.interpolation = interpolation
self.transform = transform
#a pdf can not be negative
assert(np.all(pdf>=0))
#sort the pdf by magnitude
if self.sort:
self.sortindex = np.argsort(self.pdf, axis=None)
self.pdf = self.pdf[self.sortindex]
#construct the cumulative distribution function
self.cdf = np.cumsum(self.pdf)
@property
def ndim(self):
return len(self.shape)
@property
def sum(self):
"""cached sum of all pdf values; the pdf need not sum to one, and is imlpicitly normalized"""
return self.cdf[-1]
def __call__(self, N):
"""draw """
#pick numbers which are uniformly random over the cumulative distribution function
choice = np.random.uniform(high = self.sum, size = N)
#find the indices corresponding to this point on the CDF
index = np.searchsorted(self.cdf, choice)
#if necessary, map the indices back to their original ordering
if self.sort:
index = self.sortindex[index]
#map back to multi-dimensional indexing
index = np.unravel_index(index, self.shape)
index = np.vstack(index)
#is this a discrete or piecewise continuous distribution?
if self.interpolation:
index = index + np.random.uniform(size=index.shape)
return self.transform(index)
if __name__=='__main__':
shape = 3,3
pdf = np.ones(shape)
pdf[1]=0
dist = Distribution(pdf, transform=lambda i:i-1.5)
print dist(10)
import matplotlib.pyplot as pp
pp.scatter(*dist(1000))
pp.show()
Und als mehr der realen Welt:
x = np.linspace(-100, 100, 512)
p = np.exp(-x**2)
pdf = p[:,None]*p[None,:] #2d gaussian
dist = Distribution(pdf, transform=lambda i:i-256)
print dist(1000000).mean(axis=1) #should be in the 1/sqrt(1e6) range
import matplotlib.pyplot as pp
pp.scatter(*dist(1000))
pp.show()
Sie können nur Ihre Funktion N-mal anrufen.Sie müssen jedoch noch angeben, von welcher Distribution Sie Ihre x-Werte auswählen möchten. – BrenBarn
Meine Verteilung ist meine Funktion. Ich muss diese Funktion zufällig N mal zwischen einem bestimmten Intervall auswerten. – Gabriel
Ihre Funktion ist keine Verteilung. Sie müssen entscheiden, wie die Verteilung in den Argumenten aussieht, mit denen Sie sie aufrufen. Wenn Sie N zufällige Werte "zwischen einem bestimmten Intervall" übergeben möchten, wo geben Sie dieses Intervall in Ihrem Codebeispiel an? Möchten Sie, dass die zufälligen x-Werte aus diesem Intervall oder auf andere Weise einheitlich ausgewählt werden? – BrenBarn