【问题标题】:Generator that is based on another generator基于另一个生成器的生成器
【发布时间】:2018-12-11 03:18:23
【问题描述】:

我的任务实际上很简单,但我不知道如何实现它。我打算在我的 ML 算法中使用它,但让我们简化示例。假设有一个像下面这样的生成器:

nums = ((i+1) for i in range(4))

以上内容将产生1234

假设上述生成器返回单个“样本”。我想编写一个生成器方法来批量处理它们。假设批量大小为2。所以如果调用这个新方法:

def batch_generator(batch_size):
    do something on nums
    yield batches of size batch_size

然后这个批处理生成器的输出将是:12,然后是 34。元组/列表无关紧要。重要的是如何退回这些批次。我找到了 Python 3.3 中引入的这个 yield from 关键字,但在我的情况下它似乎没有用。

很明显,如果我们有5 nums 而不是4,并且batch_size2,我们将省略第一个生成器的最后一个生成值。

【问题讨论】:

  • 参见itertools 文档中的grouper 配方。

标签: python python-3.x yield-keyword


【解决方案1】:

我自己的解决方案可能是,

nums = (i+1 for i in range(4))

def giveBatch(gen, numOfItems):
    try:
        return [next(gen) for i in range(numOfItems)]
    except StopIteration:
        pass

giveBatch(nums, 2)
# [1, 2]
giveBatch(nums, 2)
# [3, 4]

另一个解决方案是使用@Bharel 提到的grouper。我比较了运行这两种解决方案所需的时间。没有太大区别。估计可以忽略。

from timeit import timeit

def wrapper(func, *args, **kwargs):
    def wrapped():
        return func(*args, **kwargs)
    return wrapped

nums = (i+1 for i in range(1000000))

wrappedGiveBatch = wrapper(giveBatch, nums, 2)
timeit(wrappedGiveBatch, number=1000000)
# ~ 0.998439

wrappedGrouper = wrapper(grouper, nums, 2)
timeit(wrappedGrouper, number=1000000)
# ~ 0.734342

【讨论】:

  • 喜欢它。如果批次没有足够的样本,则会抛出 StopIteration。非常感谢!
  • @isquared-KeepitReal 是的,我只是补充一下,不客气 :)
  • 或者不扔:)) 哈哈
  • 25% 的迭代速度已经相当快了 ;-)
【解决方案2】:

itertools 下,您有一个代码 sn-p 可以做到这一点:

from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

您不必每次都调用一个方法,而是有一个迭代器,它可以返回批次,效率更高、速度更快,并且可以处理诸如过早用完数据等极端情况而不会丢失数据。

【讨论】:

    【解决方案3】:

    这正是我需要的:

    def giveBatch(numOfItems):
        nums = (i+1 for i in range(7))
    
        while True:
            yield [next(nums) for i in range(numOfItems)]
    

    【讨论】:

    • 很高兴您找到了解决方案,而不是定义nums static,最好将其传递给函数并以更通用和灵活的方式完成您的工作。这样您就可以将giveBatch 与任何生成器一起使用。
    • 没错,我会重构 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    • 2011-09-09
    • 1970-01-01
    • 2012-07-15
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    相关资源
    最近更新 更多