如何使用Python将2.7GB的GCT文件转换为可处理的pandas DataFrame
2.7GB GCT文件Python处理实操方案
先优化GCT原生读取逻辑
GCT是基因表达类的专用TSV格式,自带2行头部元数据,很多人读的时候没做特殊处理,会额外浪费很多内存:
- 读取时直接跳过前2行元数据,用
pd.read_csv()时指定skiprows=2, sep='\t',避免pandas把元数据识别为无效行/表头,额外占用内存。 - 强制指定所有列的数据类型,不要让pandas自动推断:前两列通常是基因名、注释信息,指定为
str即可,后续所有表达量列统一指定为float32,比默认的float64直接减少一半内存占用。可以先只读3行拿到完整列名,构造dtype字典后再全量读取,代码示例:
import pandas as pd import numpy as np import gc # 先读表头 header = pd.read_csv("input.gct", sep="\t", skiprows=2, nrows=0).columns.tolist() dtype_dict = {header[0]: str, header[1]: str} dtype_dict.update({col: np.float32 for col in header[2:]}) # 读全量数据,不需要注释列的话直接把header[1]从usecols里删掉 df = pd.read_csv("input.gct", sep="\t", skiprows=2, dtype=dtype_dict, usecols=[c for c in header if c != header[1]])
- 如果注释列(第二列)后续用不到,直接用
usecols参数排除,进一步减少内存占用。
分块处理的正确写法
之前分块失败大概率是最后把所有块合并成了全量DataFrame,等于白做分块,正确逻辑是把计算拆成两次分块遍历:
- 第一次遍历只计算归一化需要的全局统计量(比如z-score需要的均值、标准差,min-max归一化需要的最大值、最小值),只存统计值不存原始数据。
- 第二次遍历逐块用之前算好的全局统计量做归一化,处理完一块就直接追加到输出文件,全程内存只存单块数据。
- 分块大小可以按行设置,推荐单块内存占用不超过可用内存的1/10,比如8G可用内存的话设置
chunksize=10000即可,可根据实际运行情况调整。
低内存配置下的替代方案
如果可用内存小于4G,手动分块还是跑不动,可以用以下方案:
- 用dask.dataframe替代pandas,API和pandas几乎完全一致,底层自动做分块运算,支持处理远大于内存的数据集,不需要自己写分块逻辑,归一化计算完成后直接导出结果到文件即可,不需要把全量数据加载到内存。
- 先用shell预处理裁剪不必要的列/行,效率远高于Python内处理,比如要保留第1列和第3到第500列的话,直接运行
cut -f 1,3-500 input.gct > trimmed.gct,得到裁剪后的文件再进Python处理。 - 处理后的结果建议存为HDF5格式,用
pd.HDFStore分块写入,后续读取也支持按需拉取子集,比纯文本格式IO效率高10倍以上,内存占用也小很多。
内存问题排查
如果还是出现内存溢出,先运行df.memory_usage(deep=True).sum() / 1024**3查看数据实际内存占用,如果远大于2.7G,肯定是有列被识别为object类型,检查dtype设置是否正确。处理过程中及时用del删除不用的中间变量,再调用gc.collect()释放内存,避免内存碎片堆积。
内容的提问来源于stack exchange,提问作者Noa164
相关产品推荐
相关产品推荐

