使用 python 生成器处理大型文本文件
using a python generator to process large text files
我刚开始使用生成器并阅读了一些内容,但需要一些帮助来处理成块的大文本文件。我知道这个话题已经被涵盖了,但是示例代码的解释非常有限,如果不明白发生了什么,就很难修改代码。
我的问题相当简单,我有一系列包含以下格式的人类基因组测序数据的大型文本文件:
chr22 1 0
chr22 2 0
chr22 3 1
chr22 4 1
chr22 5 1
chr22 6 2
文件长度在 1Gb 到 ~20Gb 之间,太大而无法读入 RAM。所以我想一次读取 chunks/bins 中的行,比如 10000 行,这样我就可以在这些 bin 大小的最后一列上执行计算。
基于此link here我写了以下内容:
def read_large_file(file_object):
"""A generator function to read a large file lazily."""
bin_size=5000
start=0
end=start+bin_size
# Read a block from the file: data
while True:
data = file_object.readlines(end)
if not data:
break
start=start+bin_size
end=end+bin_size
yield data
def process_file(path):
try:
# Open a connection to the file
with open(path) as file_handler:
# Create a generator object for the file: gen_file
for block in read_large_file(file_handler):
print(block)
# process block
except (IOError, OSError):
print("Error opening / processing file")
return
if __name__ == '__main__':
path='C:/path_to/input.txt'
process_file(path)
在 'process_block' 内 我期望返回的 'block' 对象是一个 10000 个元素长的列表,但它不是?第一个列表是 843 个元素。第二个是2394个元素?
我想返回块中的 'N' 行数,但对这里发生的事情感到很困惑?
这个解决方案 here 似乎可以提供帮助,但我还是不明白如何修改它以一次读取 N 行?
这个 here 看起来也是一个非常好的解决方案,但同样,没有足够的背景解释让我无法理解足以修改代码。
任何帮助将不胜感激?
与其使用文件中的偏移量,不如尝试从循环中构建并生成包含 10000 个元素的列表:
def read_large_file(file_handler, block_size=10000):
block = []
for line in file_handler:
block.append(line)
if len(block) == block_size:
yield block
block = []
# don't forget to yield the last block
if block:
yield block
with open(path) as file_handler:
for block in read_large_file(file_handler):
print(block)
如果它能帮助其他遇到类似问题的人,这里是一个基于 here
的解决方案
import pandas as pd
def process_file(path,binSize):
for chunk in pd.read_csv(path, sep='\t', chunksize=binSize):
print(chunk)
print(chunk.ix[:,2]) # get 3rd col
# Do something with chunk....
if __name__ == '__main__':
path='path_to/infile.txt'
binSize=5000
process_file(path,binSize)
不是正确答案,但找出此行为的原因大约需要 27 秒:
(blook)bruno@bigb:~/Work/blookup/src/project$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
pythonrc start
pythonrc done
>>> help(file.readlines)
Help on method_descriptor:
readlines(...)
readlines([size]) -> list of strings, each a line from the file.
Call readline() repeatedly and return a list of the lines so read.
The optional size argument, if given, is an approximate bound on the
total number of bytes in the lines returned.
我明白并不是这里的每个人都是专业程序员 - 当然 文档并不总是足以解决问题(我很乐意回答这类问题) , 但实际上在文档开头用普通字母写答案的问题数量确实有点烦人。
我刚开始使用生成器并阅读了一些内容,但需要一些帮助来处理成块的大文本文件。我知道这个话题已经被涵盖了,但是示例代码的解释非常有限,如果不明白发生了什么,就很难修改代码。
我的问题相当简单,我有一系列包含以下格式的人类基因组测序数据的大型文本文件:
chr22 1 0
chr22 2 0
chr22 3 1
chr22 4 1
chr22 5 1
chr22 6 2
文件长度在 1Gb 到 ~20Gb 之间,太大而无法读入 RAM。所以我想一次读取 chunks/bins 中的行,比如 10000 行,这样我就可以在这些 bin 大小的最后一列上执行计算。
基于此link here我写了以下内容:
def read_large_file(file_object):
"""A generator function to read a large file lazily."""
bin_size=5000
start=0
end=start+bin_size
# Read a block from the file: data
while True:
data = file_object.readlines(end)
if not data:
break
start=start+bin_size
end=end+bin_size
yield data
def process_file(path):
try:
# Open a connection to the file
with open(path) as file_handler:
# Create a generator object for the file: gen_file
for block in read_large_file(file_handler):
print(block)
# process block
except (IOError, OSError):
print("Error opening / processing file")
return
if __name__ == '__main__':
path='C:/path_to/input.txt'
process_file(path)
在 'process_block' 内 我期望返回的 'block' 对象是一个 10000 个元素长的列表,但它不是?第一个列表是 843 个元素。第二个是2394个元素?
我想返回块中的 'N' 行数,但对这里发生的事情感到很困惑?
这个解决方案 here 似乎可以提供帮助,但我还是不明白如何修改它以一次读取 N 行?
这个 here 看起来也是一个非常好的解决方案,但同样,没有足够的背景解释让我无法理解足以修改代码。
任何帮助将不胜感激?
与其使用文件中的偏移量,不如尝试从循环中构建并生成包含 10000 个元素的列表:
def read_large_file(file_handler, block_size=10000):
block = []
for line in file_handler:
block.append(line)
if len(block) == block_size:
yield block
block = []
# don't forget to yield the last block
if block:
yield block
with open(path) as file_handler:
for block in read_large_file(file_handler):
print(block)
如果它能帮助其他遇到类似问题的人,这里是一个基于 here
的解决方案import pandas as pd
def process_file(path,binSize):
for chunk in pd.read_csv(path, sep='\t', chunksize=binSize):
print(chunk)
print(chunk.ix[:,2]) # get 3rd col
# Do something with chunk....
if __name__ == '__main__':
path='path_to/infile.txt'
binSize=5000
process_file(path,binSize)
不是正确答案,但找出此行为的原因大约需要 27 秒:
(blook)bruno@bigb:~/Work/blookup/src/project$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
pythonrc start
pythonrc done
>>> help(file.readlines)
Help on method_descriptor:
readlines(...)
readlines([size]) -> list of strings, each a line from the file.
Call readline() repeatedly and return a list of the lines so read.
The optional size argument, if given, is an approximate bound on the
total number of bytes in the lines returned.
我明白并不是这里的每个人都是专业程序员 - 当然 文档并不总是足以解决问题(我很乐意回答这类问题) , 但实际上在文档开头用普通字母写答案的问题数量确实有点烦人。