簡體   English   中英

基於另一台發電機的發電機

[英]Generator that is based on another generator

我的任務實際上很簡單,但是我不知道如何實現它。 我打算在我的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 元組/列表無關緊要。 重要的是如何退回這些批次。 yield from Python 3.3中引入的關鍵字中發現了這種yield from ,但是對於我來說似乎沒有用。

顯然,如果我們用5 num而不是4 ,並且batch_size2 ,我們將忽略第一個生成器的最后一個產生的值。

我自己的解決方案可能是

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

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)

您不必每次都調用方法,而是擁有一個迭代器,該迭代器可以更高效,更快速地返回批處理,並且可以處理一些極端情況,例如過早耗盡數據而不會丟失數據。

這正是我所需要的:

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

    while True:
        yield [next(nums) for i in range(numOfItems)]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM