Python 采样柱状图,使样本上的总和均匀

Python 采样柱状图,使样本上的总和均匀,python,numpy,statistics,sampling,Python,Numpy,Statistics,Sampling,我有一个项目列表,我想从中随机抽取一个子集,但每个项目都与D个箱子上的柱状图配对,我想以这样一种方式对项目进行抽样,即汇总柱状图大致一致 因此,它应作为以下示例函数工作: >>> import numpy >>> #The histograms from which to sample (each having 5 bins): >>> data = numpy.random.randint(100, size=(10000,5)) >

我有一个项目列表,我想从中随机抽取一个子集,但每个项目都与D个箱子上的柱状图配对,我想以这样一种方式对项目进行抽样,即汇总柱状图大致一致

因此,它应作为以下示例函数工作:

>>> import numpy
>>> #The histograms from which to sample (each having 5 bins):
>>> data = numpy.random.randint(100, size=(10000,5))
>>> #The function which I'm trying to program:
>>> samples = sample(data,500)
>>> samples.shape
(500,5)
>>> summed_histogram = samples.sum(axis=0)
>>> #Each bin should have approximately equal value
>>> summed_histogram / float(summed_histogram.sum())
array([ 0.2,  0.2,  0.2,  0.2,  0.2])

求和直方图的绝对值并不重要,也不需要完全一致,只需要近似一致。此外,我不在乎返回的样本大小是否与指定的样本大小不完全一致。抽样应无需更换。

您是否可以抽取一些完整的随机样本(500个),然后选择一个最均匀的样本(即最低的
sample.sum(axis=0).std()
)?这避免了在绘制增量样本时出现奇怪的偏差。

要扩展@Ilmari Karonen的解决方案,您需要做的是计算每个直方图的权重,然后根据这些权重进行采样。在我看来,考虑到你的目标,最有效的方法是使用

设D_ij为第i项直方图中第j个箱子的重量。然后,如果用权重w_i对每个项目进行加权,则“求和直方图”将具有权重和(项目中的i)w_i D_ij。获得“近似均匀”分布的一种方法是最大限度地减小箱子之间的最大差异,因此我们将解决以下LP:

minimize z
subject to (for all j, k) 
    z >= (sum i in items) w_i D_ij - (sum i in items) w_i D_ik
    z >= (sum i in items) w_i D_ik - (sum i in items) w_i D_ij
以上基本上是说,
z>=
所有加权的箱子对之间的差异绝对值。要解决此LP,您需要一个单独的包,因为numpy不包括LP解算器。有关使用
cplex
的解决方案或使用
cvxpy
的解决方案,请参阅。请注意,您需要像这些解决方案那样对权重设置一些约束(例如,每个权重都大于或等于0)。GLPK(GNU线性编程工具包)的其他python绑定可在此处找到:

最后,您只需使用权重从直方图
i
中采样。这可以通过使用@Ilmari Karonen建议的
cumsum
searchsorted
调整轮盘赌选择来实现,请参阅

如果您希望得到的加权分布“尽可能均匀”,我将解决一个类似的加权问题,但要最大化箱子加权和的加权熵。尽管可以使用任意数量的非线性解算器(如BFG或基于梯度的方法),但该问题似乎是非线性的。这可能比LP方法慢一点,但这取决于应用程序中需要什么。如果有大量直方图,LP方法将非常接近非线性方法,因为它很容易达到均匀分布

当使用LP解决方案时,一组直方图权重可能会绑定到0,因为约束的数量很小,但这对于非平凡数量的箱子来说不是问题,因为约束的数量是O(n^2)

具有50个直方图和10个箱子的权重示例:

[0.006123642775837011, 0.08591660144140816, 0.0, 0.0, 0.0, 0.0, 0.03407525280610657, 0.0, 0.0, 0.0, 0.07092537493489116, 0.0, 0.0, 0.023926802333318554, 0.0, 0.03941537854267549, 0.0, 0.0, 0.0, 0.0, 0.10937063438351756, 0.08715770469631079, 0.0, 0.05841899435928017, 0.016328676622408153, 0.002218517959171183, 0.0, 0.0, 0.0, 0.08186919626269101, 0.03173286609277701, 0.08737065271898292, 0.0, 0.0, 0.041505225727435785, 0.05033635148761689, 0.0, 0.09172214842175723, 0.027548495513552738, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0259929997624099, 0.0, 0.0, 0.028044483157851748, 0.0, 0.0, 0.0]
有50个柱状图,每个柱状图有50个箱子,现在零值很少:

[0.0219136051655165, 0.0, 0.028325808078797768, 0.0, 0.040889043180965624, 0.04372501089775975, 0.0, 0.031032870504105477, 0.020745831040881676, 0.04794861828714149, 0.0, 0.03763592540998652, 0.0029093177405377577, 0.0034239051136138398, 0.0, 0.03079554151573207, 0.0, 0.04676278554085836, 0.0461258666541918, 9.639105313353352e-05, 0.0, 0.013649362063473166, 0.059168272186891635, 0.06703936360466661, 0.0, 0.0, 0.03175895249795131, 0.0, 0.0, 0.04376133487616099, 0.02406633433758186, 0.009724226721798858, 0.05058252335384487, 0.0, 0.0393763638188805, 0.05287112817101315, 0.0, 0.0, 0.06365320629437914, 0.0, 0.024978299494456246, 0.023531082497830605, 0.033406648550332804, 0.012693750980220679, 0.00274892002684083, 0.0, 0.0, 0.0, 0.0, 0.04465971034045478, 4.888224154453002]

另外,我想取样的项目是图像块,直方图是手动分割图像的标签直方图。您可以做的是首先为项目选择权重,使加权和(近似)一致,然后对项目进行加权取样。第一部分是多元优化问题,第二部分相对简单,例如使用
cumsum()
计算CDF和
searchsorted()
对其进行采样。问题是,这些样本中任何一个的分布与数据集分布非常不同的概率都非常小。为了有机会画出一个大致均匀的样品,我必须要画的样品数量太多了。这似乎是一条路要走。在接受它作为答案之前,我会试一试。太好了,如果我能帮上什么忙,请告诉我。我在许多应用程序中使用了Java的LP和非线性解算器。我必须添加一个约束条件,即所有
w>=0
,然后我使它工作起来,请参阅
cvxpy
中的问题要点:我用我的回复更新了帖子。很抱歉,我的python知识很差。好吧……当你这么做的时候,我花了一个小时试图学习python:D