【问题标题】:Astropy, Numpy: Applying function over coordinates is very slowAstropy,Numpy:在坐标上应用函数非常慢
【发布时间】:2017-11-24 07:18:56
【问题描述】:

我在单个天体坐标对象中包含大量坐标。我想对每个坐标并行应用一个函数,并生成一个相同形状的输出数组——但这很慢。

(在我的例子中,该函数是一个模型,它采用星系中心坐标并输出与空间中该点相关的“亮度”。)

插图:

In [339]: type(data)
Out[339]: astropy.coordinates.builtin_frames.galactocentric.Galactocentric

In [340]: data.shape, data.size              # Not that big, really
Out[340]: ((21, 21, 31), 13671)

In [341]: data[0,0,0]                        # An example of a single coordinate
Out[341]: 
<Galactocentric Coordinate (galcen_distance=8.3 kpc, galcen_ra=266d24m18.36s, galcen_dec=-28d56m10.23s, z_sun=27.0 pc, roll=0.0 deg): (rho, phi, z) in (kpc, deg, kpc)
    ( 8.29995608,  180.,  0.027)>

In [342]: func = vectorize(lambda coord: 0)  # Dummy function

In [343]: %time func(data).shape
CPU times: user 33.2 s, sys: 88.1 ms, total: 33.3 s
Wall time: 33.4 s
Out[343]: (21, 21, 31)

我怀疑这很慢,因为在每次迭代中,都会初始化一个新的坐标对象,然后再将其传递给矢量化函数 (discussion)。

解决方案可能是在应用函数之前将坐标对象转换为普通的 numpy 数组,丢弃单元信息和元数据(因为单元是同质的)。

但是,我找不到这样做的方法。


我应该如何处理这个问题?如果转换为 vanilla numpy 数据类型是最好的解决方案,那是如何实现的?

谢谢!


最小的工作示例:

from numpy import *
from astropy import units as u
from astropy.coordinates import Galactocentric

# Generate lots of coordinates
x = linspace(0, 1, 1e3)*u.pc
data = Galactocentric(x=x, y=0*u.pc, z=0*u.pc)

@vectorize
def func(coord):
    '''ultimately in terms of coord.x, coord.y, coord.z...'''
    return 0

# timeit
func(data)

【问题讨论】:

  • 我通常会通过data.si.value删除单位。
  • 在我的例子中,data.data(哎呀——不幸的命名)是一个无量纲的&lt;CartesianRepresentation … &gt; 对象,它位于不同的坐标系中。我的data 对象具有(rho, phi, z) 坐标,这是我的模型所需要的。
  • 在我喜欢使用%timeit。 np.vectorize 不会产生快速编译的代码;阅读其速度免责声明。如果没有有关您的功能的信息,我们将无能为力。
  • 问题不在于我的功能。即使是带有返回零的函数的简单示例仍然很慢。问题在于我如何迭代坐标。用我的复杂函数迭代一个普通的 numpy 数组确实非常快。
  • 请参阅github.com/astropy/astropy/issues/3323 了解有关此问题的一些长期讨论。认识到这是一个真正的问题,与初始化坐标对象有关。也许fastiter() 解决方案对您有用,如果您同意,请在 github 上投票。

标签: python numpy astropy


【解决方案1】:

一种解决方案(但不是最好的——参见编辑)是将 astropy 坐标转换为 numpy 数组,然后使用 numpy.这种转换可以通过分别提取每个坐标分量来完成:

coords_np = stack([coords.rho, coords.phi, coords.z]).value

(由于生成的数组会包含混合单元,因此我们通过采用.value 来丢弃单元。)

现在,坐标三元组(rho, phi, z) 沿着新轴,

>>> coords_np[:,0,0,0]
array([  <rho>,  <phi>,    <z>])

你可以像这样将你的函数(rho, phi, z) -&gt; x 应用到coords_np:

scalar_field = apply_along_axis(func, 0, coords_np)

这个结果相当于执行func(coords)(直接在天体坐标上),但速度更快。


编辑:如果可能,通过矢量化函数来完全避免apply_along_axis,而不是将其应用于每个坐标。例如,如果函数类似于lambda rho, phi, z: rho**2 + z**2,那么简单地计算coords.rho**2 + coords.z**2 比在stack([coords.rho, coords.phi, coords.z]) 上迭代该函数要快得多。这具有保留单位的额外优势。

见this answer。

【讨论】:

    猜你喜欢
    • 2023-02-04
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 2011-08-11
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多