【问题标题】:Adapting a sliding-window Python generator function to shuffle the window调整滑动窗口 Python 生成器函数以随机播放窗口
【发布时间】:2019-12-17 12:31:47
【问题描述】:

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

下面的代码是这样做的:我使用滑动窗口函数在大约 250 个字符的窗口中迭代一个 5,500 个字符的字符串(约 5,500 bp 的 DNA 序列),步长为 1。对于每个块,我将其 GC 内容与 750 行文件中的一行进行比较。 (GC 内容是等于 G 或 C 的字符串元素的百分比)。

但是,对于我的下游用途,我真的很想随机循环这些块。从我的 Stack Overflow 搜索中,我了解到无法对生成器对象进行混洗,并且我无法在函数内混洗窗口,因为它实际上一次搜索一个窗口,返回到下一个块的函数,因为那个“产量”。 (如果我误解了,请纠正我)。

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

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 次。我可以做?生成器似乎是我想做的一个优雅的解决方案,除了现在我决定要随机化块顺序。显然我需要牺牲效率来做到这一点,但我想知道更有经验的编码人员是否有一些聪明的解决方案。谢谢!

【问题讨论】:

    标签: python random generator shuffle sliding-window


    【解决方案1】:

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

    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)
    

    【讨论】:

    • 太棒了。这就是我想做的……我应该知道它会涉及到 numpy。我刚开始使用 Python(屈服于人们试图让我脱离 Perl 培训的压力),我一直听说学习 numpy 会改变我的生活。我想我应该继续这样做。谢谢!!!
    【解决方案2】:

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

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

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

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

    【讨论】:

    • 谢谢!对不起,如果我不完全清楚。 1) 输入文件每一行的 GC 变化。 2)。我对如何做到这一点完全灵活......有时我会陷入僵化的方法,这就是我寻求建议的原因。我所关心的只是在遍历它们之前随机化这些块。我认为您的解决方案会创建一个列表而不是使用生成器函数 - 我会试试这个!这是我能想到的随机化块顺序的唯一方法。谢谢!它很好,简洁......我喜欢它。
    • 是的,这会将块添加到列表中,然后您可以使用 random.shuffle() 对其进行随机播放。如果您想进一步研究,生成列表的特定方法称为列表理解。希望它有效!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    • 2021-08-15
    • 1970-01-01
    • 2016-03-06
    • 1970-01-01
    相关资源
    最近更新 更多