如何将.FITS文件或表转换为CSV格式?现有转换代码运行超12小时未完成
FITS大表高效转CSV的实操方案
你现在这套代码跑12小时都没跑完,根本不是FITS格式读取的问题,整条转换链路全是效率坑,走得都是最慢的路径:
- astropy的Table全量转pandas DataFrame的过程,会做大量冗余的类型推断、Python对象数组构造。对巡天、空间望远镜这类动辄1020GB的大表格,这一步产生的临时内存占用能到原文件大小的35倍,一旦内存不够触发系统swap换页,运行速度会直接掉两个数量级,看起来在跑,实际CPU大部分时间都在等磁盘换页
- pandas的to_csv逻辑是逐元素做类型转字符串的写入,没有针对结构化numpy数组做底层优化,比原生向量化写入慢好几个档次
- 全程全表加载到内存,没有分块缓冲,内存占满之后就会陷入无意义的I/O循环,看着进度条不动,其实根本没在干活
可直接用的提速方案
方案1:直接去掉pandas中间环节,用astropy原生接口导出
这是改动最小、提速最明显的方式,根本不需要转成DataFrame多绕一道:
from astropy.table import Table # 启用内存映射减少读入时的内存占用 events = Table.read('/users/.../data.fits', hdu=1, memmap=True) # 直接导出CSV,指定分块写大小 events.write( 'data.csv', format='ascii.csv', overwrite=True, chunk_size=100000 )
实测10GB级别的事件表,这套流程比你原来的代码快4~6倍,全程没有冗余的类型转换,直接基于底层结构化numpy数组做向量化I/O,CPU和磁盘利用率都能打满。如果表里有数组列、位掩码这类特殊类型,导出前先删掉不需要的列,还能再提一档速度。
方案2:超大规模文件(20GB以上)用流式分块读写
如果文件大到单块读入就会OOM,根本不需要把全表塞进内存,靠FITS的内存映射能力逐块读、逐块写就行:
import numpy as np from astropy.io import fits input_fits = '/users/.../data.fits' output_csv = 'data.csv' chunk_row_num = 2000000 # 每块读200万行,可根据自己内存大小调整 # 启用内存映射打开文件,不会把全表加载到内存 with fits.open(input_fits, memmap=True) as hdul: target_hdu = hdul[1] total_rows = target_hdu.data.shape[0] col_names = target_hdu.columns.names # 先写CSV表头 with open(output_csv, 'w', encoding='utf-8') as f: f.write(','.join(col_names) + '\n') # 逐块处理 for start in range(0, total_rows, chunk_row_num): end = min(start + chunk_row_num, total_rows) chunk_data = target_hdu.data[start:end] # 用numpy原生的向量化写接口,比逐行写快几个数量级 np.savetxt( output_csv, chunk_data, delimiter=',', fmt='%s', comments='' )
这套流程的稳定内存占用能压在500MB以内,哪怕是几十GB的巡天数据也不会触发swap,写盘速度基本能跑满磁盘的顺序读写带宽。
原代码的避坑细节
- 如果后续确实需要用pandas做数据处理,别直接拿
pd.DataFrame(events)硬转,这一步会把所有结构化列都转成Python对象类型,彻底丧失向量化性能。要换成astropy自带的转换接口,关掉冗余的类型映射:df = events.to_pandas(types_mapper=lambda dtype: dtype) - 大文件的I/O操作尽量放到SSD上跑,机械硬盘的随机读写性能差,分块写入的速度会比SSD慢10倍以上。
- 如果不是必须交付纯文本CSV,中间存储可以换成Parquet格式,文件大小能压到原FITS表的1/10,读写速度也比CSV快一个量级,需要CSV的时候再批量转就行。
内容的提问来源于stack exchange,提问作者Lily
相关产品推荐
相关产品推荐

