在二代、三代测序背景下,分析人员难免会遇到解析超过1G、或者10G以上的文件。这里将给大家简单介绍下如何用python读取大文件,并给大家提两个优化代码的小建议。
首先,python 读取GB级大文件,常规使用open() 内置函数进行打开操作。
python打开文件后,在进行读取内容时分三种情况:
(1)read() 读取整个文件,通常将文件内容放到一个字符串变量中;
(2)readline() 每次读取一行内容;
(3)readlines() 一次性读取所有内容并按行返回list;
当文件较大时,使用read() 函数将文件内容全部读取到内存中,当文件大小超过内存是,可能会导致内存溢出,此时可以定义一个tmp_size,即每次读取的文件大小,如下,tmp_size为2M大小:
但是在读取大文件时,不是内存溢出、就是需要自定义tmp_size大小,所以,这里推荐大家用with open()函数,它可以让系统自动进行IO缓存和内存管理,不需要管系统怎么去分配这些内存,并且在读取完毕之后,不需要手动去close() 文件句柄。
随后,这里讲解下python对于文件打开时的操作模式:
我们最常用的就是三种模式'r'、'w'、'a'。读取文件信息时,采用'r'(read);写文件时分两种,一个是追加、一个是覆盖重写,分别对应'a'(append)和'w'(write),这两种模式对于不存在的文件首先会进行创建。
既然已经读取了文件内容,那下面就是需要对文件内容进行提取、存储,在存储方面,我们最常用的是list,以及dict。下面我们将就这两种数据类型进行优化技巧说明:
首先list,如果数据量很小,那用list还是set没有分别,但是如果你需要保存超过100的元素时,建议换成set()【这个set简直不要太好用啊~~】,set() 数据集在分析过程中不管是添加元素(add)还是判断元素是否存在,都会比list快至少1倍以上(当然数据越大,越明显)。作者曾经试过在list中存储1千个以上元素时,判断元素是否存在这个过程将非常耗时,但如果用set,整体时间将大大缩短【感觉整个人都轻松了许多】。
然后是dict,dict在存储value时,如果key对应的value是一个数组,比如基因的exon的起始位点有多个,那可以将多个起始位点的值存储为set类型,在exon较多的时候,脚本运行性能会有比较明显的提升。当然最多的时候我们对dict是进行key、value的遍历,一般遍历有两种方式:
在python2中,items() 方式返回的是一个list,那当数据很大时,会消耗大量内存,导致系统运行缓慢;而iteritems()方式返回的是一个迭代器并非列表。所以在python2中如果需要对key和value同时遍历时,采用iteritems() 效率更高。当然在python3中,对items() 的方式进行了优化,也返回迭代器,所以在python3中iteritems()的方式被取消了。