1

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

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

以上, 将产生我们1, 2,34.

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

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

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

显然,如果我们有5nums 而不是4, and batch_sizeis 2,我们将省略第一个生成器的最后一个产生的值。

4

3 回答 3

3

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

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]

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

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
于 2018-07-02T21:33:20.820 回答
1

itertools下,您有一个代码片段可以做到这一点:

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)

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

于 2018-07-02T21:39:38.067 回答
0

这正是我所需要的:

def giveBatch(numOfItems):
    nums = (i+1 for i in range(7))

    while True:
        yield [next(nums) for i in range(numOfItems)]
于 2018-07-03T17:20:30.640 回答