懒惰地在python中随机抽样

时间:2010-11-26 16:12:46

标签: python random lazy-evaluation sampling

Python问题。我正在生成大量的对象,我只需要做一个小的随机样本。实际上生成有问题的对象需要一段时间,所以我想知道是否有可能以某种方式跳过那些不需要生成的对象,只显式创建那些已经采样的对象。

换句话说,我现在有

a = createHugeArray()
s = random.sample(a,len(a)*0.001)

这是相当浪费的。我更喜欢像懒惰的东西

a = createArrayGenerator()
s = random.sample(a,len(a)*0.001)

我不知道这是否有效。 random.sample上的文档不太清楚,虽然它提到xrange非常快 - 这让我相信它可能会起作用。将数组创建转换为生成器将是一项工作(我对生成器的了解非常生疏),所以我想知道这是否有效。 :)

我可以看到的替代方法是通过xrange制作随机样本,并仅生成那些通过索引实际选择的对象。虽然这不是很干净,因为生成的索引是任意的和不必要的,我需要相当hacky逻辑来支持我的generateHugeArray方法。

对于奖励积分:random.sample实际上如何运作?特别是,如果像xrange这样的生成器不提前知道人口的大小,它是如何工作的?

4 个答案:

答案 0 :(得分:2)

似乎没有办法避免弄清楚索引如何映射到你的排列。如果您不知道这一点,您将如何从数组中创建一个随机对象?您可以使用自己建议的xrange()来使用该技巧,或者实现一个定义__getitem__()__len__()方法的类,并将此类的传递和对象作为population参数传递给{ {1}}。

进一步评论:

  • 将createHugeArray()转换为生成器不会为您带来任何好处 - random.sample()将不再适用。它需要一个支持random.sample()的对象。

  • 所以确实需要从一开始就知道人口中元素的数量。

  • implementation具有两种不同的算法,并选择使用较少内存的算法。对于相对较小的len()(即,在手头的情况下),它将简单地保存已在k中选择的索引,并且如果它击中其中一个,则进行新的随机选择。

编辑:完全不同的方法是迭代所有排列一次,并决定是否应该包括每个排列。如果排列总数为set,并且您想要选择n,则可以写

k

这会随机选择selected = [] for i in xrange(n): perm = nextPermutation() if random.random() < float(k-len(selected))/(n-i): selected.append(perm) 个排列。

答案 1 :(得分:0)

您可以使用sample创建数组索引列表,然后根据结果生成对象:

def get_object(index):
    return MyClass(index)

或类似的东西。然后使用sample生成所需的索引,并使用这些索引调用此函数:

objs = map(get_object, random.sample(range(length), 0.001 * length))

这有点间接,因为它只从可能的数组索引列表中选择。

答案 2 :(得分:0)

解释random.sample的工作原理,

random.sample(container, k)将从容器中随机返回k个值。因为生成器可以像列表,元组和dicts中的键或值一样进行迭代,它将遍历容器然后获取这些随机元素。

e.g。 random.sample(xrange(111),4)将返回[33,52,111,1]之类的k = 4,意味着xrange生成器中的4个随机数,最多为111个。

答案 3 :(得分:0)

我猜测函数createHugeArray()包含一段代码,对于每个创建的对象重复一次。而且我猜测对象是从某种初始值或种子生成的,在这种情况下createHugeArray()看起来像这样:

def createHugeArray( list_of_seeds ):
  huge_array = []                  
  for i in list_of_seeds:
    my_object = makeObject( i )
    huge_array.append( my_object )           
  return huge_array

(我使用的列表不是数组,但你明白了。)

要在实际创建对象之前进行随机抽样,只需添加一条生成随机数的行,然后仅在随机数低于某个阈值时才创建对象。假设你只需要一千个物体。 random.randint(0,999)给出一个从0到999的数字 - 所以只有在你得到零时才生成一个对象。上面的代码变为:

import random

def createHugeArray( list_of_seeds ):
  huge_array = [] 

  for i in list_of_seeds:
    die_roll = random.randint(0,999)

    if( die_roll == 0 ):
      my_object = makeObject( i )
      huge_array.append( my_object ) 
  return huge_array

当然,如果我猜测你的代码是如何工作的,那么这对你来说是没用的,在这种情况下抱歉和好运: - )