Python astropy.io适合大表的高效元素访问

Python astropy.io适合大表的高效元素访问,python,arrays,fits,astropy,Python,Arrays,Fits,Astropy,我正在尝试使用Python和astropy.io从FITS文件中的二进制表中提取数据。该表包含一个包含200多万个事件的事件数组。我想做的是将某些事件的时间值存储在一个数组中,这样我就可以对该数组进行分析。我遇到的问题是,在fortran(使用FITSIO)中,相同的操作在速度慢得多的处理器上可能需要几秒钟,而在Python中使用astropy.io进行完全相同的操作则需要几分钟。我想知道瓶颈究竟在哪里,以及是否有更有效的方法来访问各个元素,以确定是否在新数组中存储每个时间值。以下是我目前掌握的

我正在尝试使用Python和astropy.io从FITS文件中的二进制表中提取数据。该表包含一个包含200多万个事件的事件数组。我想做的是将某些事件的时间值存储在一个数组中,这样我就可以对该数组进行分析。我遇到的问题是,在fortran(使用FITSIO)中,相同的操作在速度慢得多的处理器上可能需要几秒钟,而在Python中使用astropy.io进行完全相同的操作则需要几分钟。我想知道瓶颈究竟在哪里,以及是否有更有效的方法来访问各个元素,以确定是否在新数组中存储每个时间值。以下是我目前掌握的代码:

from astropy.io import fits

minenergy=0.3
maxenergy=0.4
xcen=20000
ycen=20000
radius=50

datafile=fits.open('datafile.fits')
events=datafile['EVENTS'].data


datafile.close()

times=[]

for i in range(len(events)):
    energy=events['PI'][i]
    if energy<maxenergy*1000:
        if energy>minenergy*1000:
            x=events['X'][i]
            y=events['Y'][i]
            radius2=(x-xcen)*(x-xcen)+(y-ycen)*(y-ycen)
            if radius2<=radius*radius:
                times.append(events['TIME'][i])

print times
astropy.io导入拟合中的

矿井能量=0.3
最大能量=0.4
xcen=20000
ycen=20000
半径=50
datafile=fits.open('datafile.fits')
事件=数据文件['events']。数据
datafile.close()
时间=[]
对于范围内的i(len(events)):
能量=事件['PI'][i]
如果Energy Minenergy*1000:
x=事件['x'][i]
y=事件['y'][i]
半径2=(x-xcen)*(x-xcen)+(y-ycen)*(y-ycen)

如果radius2您需要使用numpy向量操作来完成此操作。如果没有像numba这样的特殊工具,在Python中像您这样执行大型循环总是很慢,因为它是一种解释语言。您的程序应该更像:

energy = events['PI'] / 1000.
e_ok = (energy > min_energy) & (energy < max_energy)
rad2 = (events['X'][e_ok] - xcen)**2 + (events['Y'][e_ok] - ycen)**2
r_ok = rad2 < radius**2
times = events['TIMES'][e_ok][r_ok]

非常感谢。这使得它在不到一秒钟的时间内运行。你能解释一下它用新代码做了什么,以及它与以前做的有什么不同吗?尽管Python作为一种语言很好,但它从来都不是为编写高效的数字代码而设计的。它在一个计算机科学系被设计成一种玩具语言,用来尝试一些语言设计的想法,但在那里有点流行。这就是为什么我们有像Numpy这样的包来有效地从Python代码中操作大型数值数据。我的Numpy教程可以作为一个很好的介绍:如果你要用Python编写科学代码,你必须熟悉Numpy(幸运的是,这基本上是直观的——基本上是…)。之所以速度慢,是因为表中的每一行都要从表中提取一列(
events['PI']
)它返回一个新的
ndarray
对象,表示从整个表中切片出的列,这是一个非常慢的操作。与“X”、“Y”和“TIME”相同。然后你用一个Python整数对它进行索引,它必须进入数组,寻找那个索引,然后将数值复制出来,并将其转换成Python
float
对象。另外,如果您使用的是Python 2,
range()
函数正在创建一个包含200万个Python
int
s的列表。在Python for Data Analysis第12章中,Wes McKinney建议确保数组的内存与Fortran或C顺序保持连续,以便分别在列或行上执行操作时获得最佳性能。默认情况下,numpy数组是行连续的,但一些操作(如转置)可能会改变这一点。这可以通过ndarray的flags属性进行检查。如果数组的内存顺序不是最佳的,则可以使用copy进行更改,如arr.copy('C')。将arr更改为C(行)内存顺序的标志或将arr.copy('F')。将其更改为F(列)顺序的标志。
events_filt = events[e_ok][r_ok]
times = events_filt['TIMES']