调整滑动 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 次。我可以做?对于我想做的事情,生成器似乎是一个优雅的解决方案,除了现在我已经决定要随机化块顺序。很明显我需要牺牲效率来做到这一点,但我想知道更有经验的编码人员是否有一些聪明的解决方案。谢谢!
我不是一个非常有经验的编码员(但我从事生物科学),但我有几个问题:
- 您比较滑动 window 的 GC 百分比是否始终相同?
您是否仍想按照当前的方式迭代序列?换句话说,您唯一想要更改的是生成器生成答案的顺序吗?如果是这样,你可以这样做
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)
我已经根据需要在此处调整了滑动 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 次。我可以做?对于我想做的事情,生成器似乎是一个优雅的解决方案,除了现在我已经决定要随机化块顺序。很明显我需要牺牲效率来做到这一点,但我想知道更有经验的编码人员是否有一些聪明的解决方案。谢谢!
我不是一个非常有经验的编码员(但我从事生物科学),但我有几个问题:
- 您比较滑动 window 的 GC 百分比是否始终相同?
您是否仍想按照当前的方式迭代序列?换句话说,您唯一想要更改的是生成器生成答案的顺序吗?如果是这样,你可以这样做
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)