如何创建不覆盖的空NumPy数组,替代列表实现循环追加
解决方案:直接用NumPy数组存储大规模Phred质量数据
核心思路
NumPy数组是固定大小的,直接动态追加不仅效率极低,还容易出现数据覆盖问题。针对150×180000的大规模数据,最优方案是先预分配对应尺寸的数组,再通过循环填充数据,完全跳过列表存储环节。
实现步骤
- 先遍历一次FastQ文件,统计总读取数(reads)和每条序列的碱基长度(FastQ数据通常所有序列长度一致)
- 根据统计结果预分配NumPy数组(用
uint8类型,Phred质量分范围0-60,足够存储且大幅节省内存) - 再次遍历FastQ文件,将每条序列的Phred质量数据写入数组对应位置
修改后的代码
from Bio import SeqIO import matplotlib.pyplot as plt import gzip import numpy as np # 第一步:统计数据维度 with gzip.open("data.fastq.gz", 'rt') as input_file: sio = SeqIO.parse(input_file, "fastq") total_reads = 0 read_length = None for r in sio: total_reads += 1 if read_length is None: read_length = len(r.letter_annotations['phred_quality']) # 预分配数组:维度为(total_reads, read_length),类型uint8 npa = np.zeros((total_reads, read_length), dtype=np.uint8) # 第二步:填充数组 with gzip.open("data.fastq.gz", 'rt') as input_file: sio = SeqIO.parse(input_file, "fastq") for idx, r in enumerate(sio): npa[idx] = r.letter_annotations['phred_quality'] # 绘制箱线图 plt.boxplot(npa, showfliers=False) plt.title("Quality Score Boxplot") plt.xlabel("碱基位置") plt.ylabel("读取数") plt.show()
额外优化点
- 若确定所有序列长度一致,可只取第一条序列的长度作为标准,减少一次遍历的计算量
uint8类型相比默认的int64能节省8倍内存,150×180000的数据内存占用从216MB降到27MB,大幅降低内存压力
内容的提问来源于stack exchange,提问作者voltix54
相关产品推荐
相关产品推荐

