样本整数除了指定集合中的整数之外

时间:2015-05-05 11:46:23

标签: python random-sample

假设我有一组整数exceptions = set([3, 2, 6, ...])。除了使用num[0,n)中显示的整数样本之外,从exceptions区间python均匀抽取# Create a set of the integers I am interested in integers = set(range(n)) - exceptions # Draw samples from the set samples = np.random.choice(integers, num) 整数样本的最有效方法是什么。

以下是我曾经玩过但不满意的一些想法。

n

在我的情况下,len(exceptions)相当大(大约10 ^ 12),因此创建集合似乎浪费了内存。

然而,samples = [] # Iterate until we have enough samples while len(samples) < num: # Draw a sample proposal = np.random.randint(n) # Accept or reject if proposal not in exceptions: samples.append(proposal) 相对较小(大约10 ^ 6),因此拒绝抽样可能是一种合理的方法。

C

不幸的是,所有循环和集合成员资格测试都相当缓慢。显然,我可以写一个Cython - 扩展或使用guidata(object_handle,data),但我想知道你们是否有更好的主意。

已编辑以在评论中包含建议。

1 个答案:

答案 0 :(得分:0)

我认为,如果例外情况与n相比较小,拒绝可能是您的最佳选择;请注意,使用n=10**12e=10**6获得无效结果的概率只有百万分之一,所以在大多数时间没有拒绝和重新随机的情况下你会很好。如果你还需要多个样本,那么获取大量随机数(如101%)然后将它们全部过滤掉,放弃异常可能是一个好主意(我相信有一种方法可以在循环中更快地获得多个样本) )。如果还有太多,只需截断结果;如果太少,生成更多。

随着异常的大小越来越大,您可能会尝试不同的方法:

假设您有一系列n个整数和e个例外。事实上,您有兴趣获得n-e均匀分布的结果之一。因此,如果您可以将这样的结果快速转换为有意义的结果,那么x = np.random.randint(n-e)应该足够好。首先,举例说明这个想法:

  • 我们假设n = 100,例外情况= {11,12,13,14,15,16,17,18,19,20,26,27}
  • 案例1:你的随机结果是60.你必须计算有多少例外小于或等于60:有13个。所以结果是60 + 13 = 73。
  • 案例2:您的随机结果为22.有10个例外小于此,因此您将结果增加10,得到32.但是还有两个例外不超过32,但大于22,并且因此尚未计算在内。您必须将值进一步增加2,最终结果为34。

然后,算法如下:

n = ...  # full range
exceptions = ...   # collection of your exceptions
e = len(exceptions)
def get_sample():
  x = np.random.randint(n-e)
  skipped = 0
  small_exceptions = count_small_exceptions(x, exceptions)
  while skipped < small_exceptions:
    skipped = small_exceptions
    small_exceptions = count_small_exceptions(x+skipped, exceptions)
  return x+skipped

为了实现这一点,您需要一种快速计算小于给定值的异常的方法 - 模块bisect应该这样做,因为它在排序的数组上提供二进制搜索机制。

为什么这样做?循环在skipped == small_exceptions时停止,因此skipped范围内存在0..(skipped+x)个异常。如果返回的值(skipped+x)是异常,则循环将在之前停止,因为在上一次迭代中会有更少的异常。

确切的成本分析并不容易,但如果您假设每个k常规值都有一个例外,那么后续迭代中的增加每次都会小k倍。最坏情况是exceptions=range(e)和随机x出现为0。然后会有e次迭代,每次迭代都会略有增加。如果en相比较小,这应该不是问题;否则,您可以通过将异常存储为间隔来进一步改进此解决方案,有效地将所有后续异常合并到一个“洞”和一个操作中。