Python 3.x - 如何高效地将 objects 的数组拆分成更小的批处理文件?
Python 3.x - How to efficiently split an array of objects into smaller batch files?
我是 Python 的新手,我正在尝试将一个文本文件拆分为最多 2 行的文本文件。 400objects.
我正在处理的数据是 FASTA 格式的数千个序列(带有 header 的纯文本,用于生物信息学),其中条目如下所示:
>HORVU6Hr1G000325.5
PIPPPASHFHPHHQNPSAATQPLCAAMAPAAKKPPLKSSSSHNSAAGDAA
>HORVU6Hr1G000326.1
MVKFTAEELRGIMDKKNNIRNMSVIAHVD
...
在 Biopython 中,有一个解析器 SeqIO.parse 允许将它们作为 objects 的数组进行访问,其中包含 ID 和字符串,我需要在代码的后面部分使用它们,并且因为我需要提高内存效率,所以我想避免 reading/parsing 源文件的次数超过必要的次数。
在 Biopython 手册中,推荐了一种通过生成器执行此操作的方法,我正在使用它:https://biopython.org/wiki/Split_large_file
但是,我使用的是 Python 3.7,而代码在 Python 2.x 中,因此肯定需要进行一些更改。我已经更改了
entry = iterator.next()
进入
entry = next(iterator)
但我不确定这是否是我需要更改的全部内容。
代码如下:
def batch_iterator(iterator, batch_size=400):
"""Returns lists of length batch_size."""
entry = True # Make sure we loop once
while entry:
batch = []
while len(batch) < batch_size:
try:
entry = next(iterator)
except StopIteration:
entry = None
if entry is None:
# End of file
break
batch.append(entry)
if batch:
yield batch
while True:
bsequence = input("Please enter the full path to your FASTA file(e.g. c:\folder1\folder2\protein.fasta):\n")
try:
fastafile = open(bsequence)
break
except:
print("File not found!\n")
record_iter = SeqIO.parse(fastafile,"fasta")
num = 0
for line in fastafile:
if line.startswith(">"):
num += 1
print("num=%i" % (num,))
if num > 400:
print("The specified file contains %i sequences. It's recommended to split the FASTA file into batches of max. 400 sequences.\n" % (num,))
while True:
decision = input("Do you wish to create batch files? (Original file will not be overwritten)\n(Y/N):")
if (decision == 'Y' or 'y'):
for i, batch in enumerate(batch_iterator(record_iter, 400), 1):
filename = "group_%i.fasta" % (i + 1)
with open(filename, "w") as handle:
count = SeqIO.write(batch, handle, "fasta")
print("Wrote %i records to %s" % (count, filename))
break
elif (decision == 'N' or 'n'):
break
else:
print('Invalid input\n')
...next part of the code
当我 运行 这样做时,在 Y/N 提示之后,即使我键入 Y,程序也只是跳到我的代码的下一部分而不创建任何新文件。调试器显示以下内容:
Do you wish to create batch files? (Original file will not be overwritten)
(Y/N):Y
Traceback (most recent call last):
File "\Biopython\mainscript.py", line 32, in batch_iterator
entry = next(iterator)
StopIteration
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1569, in _trace
return self._trace_and_catch(frame, event, arg)
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1611, in _trace_and_catch
frame.f_back, event, marker_function_args, node
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1656, in _handle_progress_event
self._save_current_state(frame, event, args, node)
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1738, in _save_current_state
exception_info = self._export_exception_info()
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1371, in _export_exception_info
"affected_frame_ids": exc[1]._affected_frame_ids_,
AttributeError: 'StopIteration' object has no attribute '_affected_frame_ids_'
我忽略的 Python 2.x 和 3.x 之间有什么区别吗?问题出在其他地方吗?这种做法是完全错误的吗?提前致谢!
我无法检查你的全部代码,因为你省略了一部分,但我可以在这里看到两个错误的地方:
num = 0
for line in fastafile:
if line.startswith(">"):
num += 1
这些行正在耗尽您的文件对象 fastafile
。完全删除这些行(并记住修复下面的缩进,删除 if num > 400:
检查等)。
if (decision == 'Y' or 'y'):
这与您认为的不同。将其更改为 if decision in ('Y', 'y'):
或 if decision.lower() == 'y':
。您在下面的行 if (decision == 'N' or 'n'):
中重复此模式,因此也更改它。
进行更改并再次尝试 运行 代码。
说明
第一期:在Python中,一个文件对象(即什么open('filename.txt', 'r')
returns)是一个生成器,也就是说它只能迭代一次。乍一看这似乎有点奇怪,但这就是使用生成器的全部意义所在。作为文件对象的生成器允许文件逐行循环,而不必一次加载整个文件内容——生成器只跟踪下一行。
不利的一面是它们不能倒退,因此当您编写 for line in fastafile
块时,您会耗尽生成器。当您稍后尝试调用 batch_iterator(record_iter, 400)
时,record_iter
中的生成器已经耗尽,这就是您稍后会遇到错误的原因 - 如果没有任何内容,batch_iterator
无法解析 fasta 序列留在那里进行解析。
第 2 期:对于带有布尔运算符的条件,例如 if (decision == 'Y' or 'y'):
,Python 将始终单独评估双方。所以 Python 实际上看到的是 if (bool(decision == 'Y') or bool('y')):
.
由于 bool('y')
的计算结果为 True
(就像任何非空字符串一样),您的表达式变为 if (bool(decision == 'Y') or True):
,这显然总是正确的。
使用我建议的方法之一在条件中将一个变量与多个值进行比较。
我是 Python 的新手,我正在尝试将一个文本文件拆分为最多 2 行的文本文件。 400objects.
我正在处理的数据是 FASTA 格式的数千个序列(带有 header 的纯文本,用于生物信息学),其中条目如下所示:
>HORVU6Hr1G000325.5
PIPPPASHFHPHHQNPSAATQPLCAAMAPAAKKPPLKSSSSHNSAAGDAA
>HORVU6Hr1G000326.1
MVKFTAEELRGIMDKKNNIRNMSVIAHVD
...
在 Biopython 中,有一个解析器 SeqIO.parse 允许将它们作为 objects 的数组进行访问,其中包含 ID 和字符串,我需要在代码的后面部分使用它们,并且因为我需要提高内存效率,所以我想避免 reading/parsing 源文件的次数超过必要的次数。
在 Biopython 手册中,推荐了一种通过生成器执行此操作的方法,我正在使用它:https://biopython.org/wiki/Split_large_file
但是,我使用的是 Python 3.7,而代码在 Python 2.x 中,因此肯定需要进行一些更改。我已经更改了
entry = iterator.next()
进入
entry = next(iterator)
但我不确定这是否是我需要更改的全部内容。
代码如下:
def batch_iterator(iterator, batch_size=400):
"""Returns lists of length batch_size."""
entry = True # Make sure we loop once
while entry:
batch = []
while len(batch) < batch_size:
try:
entry = next(iterator)
except StopIteration:
entry = None
if entry is None:
# End of file
break
batch.append(entry)
if batch:
yield batch
while True:
bsequence = input("Please enter the full path to your FASTA file(e.g. c:\folder1\folder2\protein.fasta):\n")
try:
fastafile = open(bsequence)
break
except:
print("File not found!\n")
record_iter = SeqIO.parse(fastafile,"fasta")
num = 0
for line in fastafile:
if line.startswith(">"):
num += 1
print("num=%i" % (num,))
if num > 400:
print("The specified file contains %i sequences. It's recommended to split the FASTA file into batches of max. 400 sequences.\n" % (num,))
while True:
decision = input("Do you wish to create batch files? (Original file will not be overwritten)\n(Y/N):")
if (decision == 'Y' or 'y'):
for i, batch in enumerate(batch_iterator(record_iter, 400), 1):
filename = "group_%i.fasta" % (i + 1)
with open(filename, "w") as handle:
count = SeqIO.write(batch, handle, "fasta")
print("Wrote %i records to %s" % (count, filename))
break
elif (decision == 'N' or 'n'):
break
else:
print('Invalid input\n')
...next part of the code
当我 运行 这样做时,在 Y/N 提示之后,即使我键入 Y,程序也只是跳到我的代码的下一部分而不创建任何新文件。调试器显示以下内容:
Do you wish to create batch files? (Original file will not be overwritten)
(Y/N):Y
Traceback (most recent call last):
File "\Biopython\mainscript.py", line 32, in batch_iterator
entry = next(iterator)
StopIteration
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1569, in _trace
return self._trace_and_catch(frame, event, arg)
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1611, in _trace_and_catch
frame.f_back, event, marker_function_args, node
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1656, in _handle_progress_event
self._save_current_state(frame, event, args, node)
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1738, in _save_current_state
exception_info = self._export_exception_info()
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1371, in _export_exception_info
"affected_frame_ids": exc[1]._affected_frame_ids_,
AttributeError: 'StopIteration' object has no attribute '_affected_frame_ids_'
我忽略的 Python 2.x 和 3.x 之间有什么区别吗?问题出在其他地方吗?这种做法是完全错误的吗?提前致谢!
我无法检查你的全部代码,因为你省略了一部分,但我可以在这里看到两个错误的地方:
num = 0
for line in fastafile:
if line.startswith(">"):
num += 1
这些行正在耗尽您的文件对象 fastafile
。完全删除这些行(并记住修复下面的缩进,删除 if num > 400:
检查等)。
if (decision == 'Y' or 'y'):
这与您认为的不同。将其更改为 if decision in ('Y', 'y'):
或 if decision.lower() == 'y':
。您在下面的行 if (decision == 'N' or 'n'):
中重复此模式,因此也更改它。
进行更改并再次尝试 运行 代码。
说明
第一期:在Python中,一个文件对象(即什么open('filename.txt', 'r')
returns)是一个生成器,也就是说它只能迭代一次。乍一看这似乎有点奇怪,但这就是使用生成器的全部意义所在。作为文件对象的生成器允许文件逐行循环,而不必一次加载整个文件内容——生成器只跟踪下一行。
不利的一面是它们不能倒退,因此当您编写 for line in fastafile
块时,您会耗尽生成器。当您稍后尝试调用 batch_iterator(record_iter, 400)
时,record_iter
中的生成器已经耗尽,这就是您稍后会遇到错误的原因 - 如果没有任何内容,batch_iterator
无法解析 fasta 序列留在那里进行解析。
第 2 期:对于带有布尔运算符的条件,例如 if (decision == 'Y' or 'y'):
,Python 将始终单独评估双方。所以 Python 实际上看到的是 if (bool(decision == 'Y') or bool('y')):
.
由于 bool('y')
的计算结果为 True
(就像任何非空字符串一样),您的表达式变为 if (bool(decision == 'Y') or True):
,这显然总是正确的。
使用我建议的方法之一在条件中将一个变量与多个值进行比较。