调整滑动 window Python 生成器函数来随机播放 window

Adapting a sliding-window Python generator function to shuffle the window

我已经根据需要在此处调整了滑动 window 生成器函数 (https://scipher.wordpress.com/2010/12/02/simple-sliding-window-iterator-in-python/)。这是我第一次接触生成器函数,所以我做了很多背景阅读。鉴于我(仍然)有限的经验,我正在征求以下问题的建议:

下面的代码执行此操作:我使用 sliding-window 函数以大约 250 个字符 windows 迭代一个 5,500 个字符的字符串(具有 ~5,500 bp 的 DNA 序列)步长为 1。对于每个块,我将其 GC 内容与 750 行文件中的一行进行比较。 (GC 含量是等于 G 或 C 的字符串元素的百分比)。

但是,对于我的下游使用,我真的很想随机循环这些块。从我的 Stack Overflow 搜索中,我了解到不可能打乱生成器对象,并且我无法在函数内部打乱 windows 因为它实际上一次搜索 windows 一个,返回到因为 "yield",下一个块的函数。 (如果我误解了,请纠正我)。

目前,我的代码看起来像这样(当然使用上面 link 中的生成器函数):

with open('/pathtofile/file.txt') as f:
    for line in f:
        line = line.rstrip()
        # For each target, grab target length (7), gc content (8)
        targ_length = line.split("\t")[8]
        gc = int(line.split("\t")[7])
        # Window size = amplicon length minus length of fwd and rev primers
        # Use a sliding window function to go along "my_seq" (5,500bp sequence). Check GC content for each window.
        chunks = slidingWindow(my_seq, targ_length, step=1)
        found = 0
        for i in chunks:
            # When GC content = same as file, save this window as the pos ctrl fragment & add primers to it
            dna_list = list(i)
            gc_count = dna_list.count("G") + dna_list.count("C")
            gc_frac = int((gc_count / len(dna_list)) * 100)
            # if (gc - 5) < gc_frac < (gc + 5):
            if gc_frac == gc:
                found = 1
                # Store this piece
                break
        if found == 0:
            # Store some info to look up later 

有人知道最佳方法吗?对我来说最明显的(也是基于 Stack Overflow 搜索)是在没有生成器函数的情况下重写它。我担心在包含大约 5,251 个元素的列表上循环 750 次。我可以做?对于我想做的事情,生成器似乎是一个优雅的解决方案,除了现在我已经决定要随机化块顺序。很明显我需要牺牲效率来做到这一点,但我想知道更有经验的编码人员是否有一些聪明的解决方案。谢谢!

我不是一个非常有经验的编码员(但我从事生物科学),但我有几个问题:

  1. 您比较滑动 window 的 GC 百分比是否始终相同?
  2. 您是否仍想按照当前的方式迭代序列?换句话说,您唯一想要更改的是生成器生成答案的顺序吗?如果是这样,你可以这样做

    import random chunks = [my_seq[i:i+targ_length] for i in range(len(seq))] random.shuffle(chunks)

我不确定我是否正确回答了你的问题,因为我不是 100% 确定它在问什么。

我相信您说得对,您不能打乱生成器的输出,但是随机化它实际生成输出的方式会相对容易。这是使用 numpy 模块随机化(并设置可选种子)的 slidingWindow 生成器函数的修改版本:

import numpy as np
def slidingWindow(sequence,winSize,step=1, seed=987):
    """Returns a generator that will iterate through
    the defined chunks of input sequence.  Input sequence
    must be iterable."""

    # Verify the inputs
    try:
        it = iter(sequence)
    except TypeError:
        raise Exception("**ERROR** sequence must be iterable.")
    if not ((type(winSize) == type(0)) and (type(step) == type(0))):
        raise Exception("**ERROR** type(winSize) and type(step) must be int.")
    if step > winSize:
        raise Exception("**ERROR** step must not be larger than winSize.")
    if winSize > len(sequence):
        raise Exception("**ERROR** winSize must not be larger than sequence length.")

    # set the seed for the pseudo-random number generator
    np.random.seed(seed)

    # Pre-compute number of chunks to emit
    numOfChunks = int(((len(sequence)-winSize)/step)+1)

    # Create a shuffled index of start points
    idx = np.arange(numOfChunks)
    np.random.shuffle(idx)

    # Do the work
    for i in range(0,numOfChunks*step,step):
        start_idx = idx[i]
        stop_idx = idx[i] + winSize
        yield sequence[start_idx:stop_idx]

然后您可以保持主代码不变,或者修改创建块的方式以设置不同的种子:

chunks = slidingWindow(my_seq, targ_length, step=1, seed=987)