非常大的数组处理与宇宙和numpy

问题描述:

由于某些原因,我需要使用天文转换comoving距离红移。基本上这涉及阅读,循环和写出列表或numpy数组......我的问题是,我的每个列表通常由〜9.5 x 10^6个元素组成。每当我尝试使用numpy.savetxt将输出保存到新的txt文件时,这会给我带来MemoryError。内存使用量快速增长,最终会减慢一点,但总是会提高128Gb的限制。非常大的数组处理与宇宙和numpy

如果有人知道我如何改进下面的脚本,我非常愿意倾听。谢谢!

import os 
import sys 
import glob 
import math 
import numpy 
import astropy 
import astropy.units as unit 
from astropy.cosmology import * 
cosmo = FlatLambdaCDM(H0=70, Om0=0.3) 

inFile=sys.argv[1] 
outFile=sys.argv[2] 

comovingDistance = numpy.loadtxt(inFile, usecols=(2,)) 

Redshift = numpy.zeros(len(comovingDistance)) 
for i in range(len(comovingDistance)): 
    Redshift[i] = z_at_value(cosmo.comoving_distance, comovingDistance[i] * unit.kpc) 

output = open(outFile,'w') 
numpy.savetxt(output, Redshift, fmt='%1.8e') 
output.close() 

下面是错误日志文件:

Traceback (most recent call last): 
    File "comoving2redshift.py", line 21, in <module> 
    Redshift[i] = z_at_value(cosmo.comoving_distance, comovingDistance[i] * unit.kpc) 
    File "/afs/mpa/home/minh/.local/lib/python2.7/site-packages/astropy/cosmology/funcs.py", line 119, in z_at_value 
    fval_zmax = func(zmax) 
    File "/afs/mpa/home/minh/.local/lib/python2.7/site-packages/astropy/cosmology/core.py", line 1195, in comoving_distance 
    return self._comoving_distance_z1z2(0, z) 
    File "/afs/mpa/home/minh/.local/lib/python2.7/site-packages/astropy/cosmology/core.py", line 1219, in _comoving_distance_z1z2 
    return self._hubble_distance * vectorize_if_needed(f, z1, z2) 
    File "/afs/mpa/home/minh/.local/lib/python2.7/site-packages/astropy/units/quantity.py", line 924, in __mul__ 
    return super(Quantity, self).__mul__(other) 
    File "/afs/mpa/home/minh/.local/lib/python2.7/site-packages/astropy/units/quantity.py", line 368, in __array_prepare__ 
    from .quantity_helper import UNSUPPORTED_UFUNCS, UFUNC_HELPERS 
MemoryError 
+0

你在哪一行得到'MemoryError'? – Divakar

+0

@Divakar我在问题中添加了错误日志文件... –

+1

[文档]中的注释(http://docs.astropy.org/en/stable/api/astropy.cosmology.z_at_value.html) z_at_value'似乎与你的案例有关,你可能想要尝试这种方法。另外,你有没有试图看看'z_at_value'是否是矢量化的?很可能你不需要迭代自己,也可以简单地执行'Redshift = z_at_value(cosmo.comoving_distance,comovingDistance * unit.kpc)'而无需分配'Redshift'数组。 – Jaime

我不知道内在的任何解决numpy的,但你可以立即书面每个解决方案文件保存一些内存分配,而不是后for循环。当numpy.savetxt()将浮点格式设置为字符串时,这节省了Redshift的内存分配以及在幕后完成的内存分配。

inFile=sys.argv[1] 
outFile=sys.argv[2] 

comovingDistance = numpy.loadtxt(inFile, usecols=(2,)) 

with open(outFile, 'w') as fp: 
    for distance in comovingDistance: 
     fp.write("{:1.8e}\n".format(
      z_at_value(cosmo.comoving_distance, distance * unit.kpc))) 

(注:未经测试)

作为一种替代我的其他建议的解决方案,可以拆分输入文件,迭代一套新的(临时)输入文件,并连接所有的输入文件在结束。 下面是一个bash包装器脚本,它在外面应该与问题中的Python脚本(一个输入文件参数,一个输出文件参数)完全相同。

#! /bin/bash                     

nlines=10000                     
input=$1                      
output=$2                      

# use a unique prefix!                   
prefix='tmpsplit'                    
split --lines=$nlines $input $prefix               

outfiles=()                      
# Assume we only split to a maximum of 26^2 files 
# This is the default for split anyway            
for filename in ${prefix}??                  
do                        
     outfile="${filename}-out"                
     ./calcdist.py $filename $outfile              
done                       

# This assumes the shells orders the glob expansion alphabetically        
cat ${prefix}*out > $output                  

# Clean up                      
rm ${prefix}*                     

您可能需要使用一个临时目录,而不是依赖于一个独特的前缀。