在python迭代器中根据条件选择其他迭代器

在 python 中,我有一个迭代器返回一个固定范围内的无限索引字符串,[0, N]称为Sampler. 实际上我有一个列表,它们所做的只是返回范围内的索引[0, N_0], [N_0, N_1], ..., [N_{n-1}, N_n].


我现在要做的是首先根据范围的长度选择这些迭代器中的一个,所以我有一个weights列表[N_0, N_1 - N_0, ...],我选择其中一个:


    iterator_idx = random.choices(range(len(weights)), weights=weights/weights.sum())[0]

接下来,我想要做的是创建一个迭代器,它随机选择一个迭代器并选择一批M样本。


class BatchSampler:

    def __init__(self, M):

        self.M = M

        self.weights = [weight_list]


        self.samplers = [list_of_iterators]

        ]

        self._batch_samplers = [

            self.batch_sampler(sampler) for sampler in self.samplers

        ]


    def batch_sampler(self, sampler):

        batch = []

        for batch_idx in sampler:

            batch.append(batch_idx)

            if len(batch) == self.M:

                yield batch


        if len(batch) > 0:

            yield batch


    def __iter__(self):

        # First select one of the datasets.

        iterator_idx = random.choices(

            range(len(self.weights)), weights=self.weights / self.weights.sum()

        )[0]

        return self._batch_samplers[iterator_idx]

问题在于它似乎iter()只被调用一次,所以只iterator_idx选择了第一次。显然这是错误的......解决这个问题的方法是什么?


当您在 pytorch 中有多个数据集时,可能会出现这种情况,但您只想从其中一个数据集中采样批次。


不负相思意
浏览 145回答 1
1回答

ibeautiful

在我看来,您想定义自己的容器类型。我尝试提供一些标准方法的示例(希望不会遗漏太多细节);您应该能够将这些简单示例之一重用到您自己的课程中。仅使用 __getitem__ (支持索引和循环):对象.__getitem__被调用以执行对自我[key]的评估。class MyContainer:  def __init__(self, sequence):    self.elements = sequence  # Just something to work with.    def __getitem__(self, key):    # If we're delegating to sequences like built-in list,     # invalid indices are handled automatically by them     # (throwing IndexError, as per the documentation).    return self.elements[key]t = (1, 2, 'a', 'b')c = MyContainer(t)elems = [e for e in c]assert elems == [1, 2, 'a', 'b']assert c[1:-1] == t[1:-1] == (2, 'a')使用迭代器协议:对象.__iter__object.__iter__(self)当容器需要迭代器时调用此方法。此方法应返回一个新的迭代器对象,该对象可以迭代容器中的所有对象。对于映射,它应该遍历容器的键。迭代器对象也需要实现这个方法;他们必须自己返回。有关迭代器对象的更多信息,请参阅迭代器类型。迭代器类型container.__iter__()返回一个迭代器对象。该对象需要支持下面描述的迭代器协议。迭代器对象本身需要支持以下两种方法,它们共同构成了迭代器协议:iterator.__iter__()返回迭代器对象本身。这是允许容器和迭代器与 for 和 in 语句一起使用所必需的。iterator.__next__()从容器中返回下一个项目。如果没有其他项目,则引发 StopIteration 异常。一旦迭代器的 __next__() 方法引发 StopIteration,它必须在后续调用中继续这样做。class MyContainer:  class Iter:    def __init__(self, container):      self.cont = container      self.pos = 0      self.len = len(container.elements)        def __iter__(self): return self    def __next__(self):      if self.pos == self.len: raise StopIteration      curElem = self.cont.elements[self.pos]      self.pos += 1      return curElem    def __init__(self, sequence):    self.elements = sequence  # Just something to work with.    def __iter__(self):    return MyContainer.Iter(self)t = (1, 2, 'a', 'b')c = MyContainer(t)elems = [e for e in c]assert elems == [1, 2, 'a', 'b']使用发电机:发电机类型Python 的生成器提供了一种实现迭代器协议的便捷方式。如果一个容器对象的iter () 方法被实现为一个生成器,它将自动返回一个迭代器对象(技术上,一个生成器对象)提供 iter ( ) 和next () 方法。发电机返回生成器迭代器的函数。它看起来像一个普通函数,只是它包含 yield 表达式,用于生成一系列可在 for 循环中使用的值,或者可以使用 next() 函数一次检索一个值。通常指代生成器函数,但在某些情况下可能指代生成器迭代器。生成器迭代器由生成器函数创建的对象。6.2.9. 产量表达式在函数体中使用 yield 表达式会使该函数成为生成器class MyContainer:  def __init__(self, sequence):    self.elements = sequence  # Just something to work with.    def __iter__(self):    for e in self.elements: yield et = (1, 2, 'a', 'b')c = MyContainer(t)elems = [e for e in c]assert elems == [1, 2, 'a', 'b']
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python