我正在用numpy和astropy用Python编写代码。在代码中,我希望创建通常类似于我的数据集的随机numpy数组。之后,我想将这些随机的球面坐标数组转换为笛卡尔坐标。不幸的是,我不断收到值错误,我完全为为什么发生这种情况感到困惑,我试图进行一些虚拟测试,例如它们是否具有相同的形状,所有数组的值都合理且具有相同的类型,等等。我被困住了。这是我的代码:
from astropy.coordinates import SkyCoord
from astropy import units as u
import numpy as np
R = 445 + np.random.randn(262615)
print(np.shape(R))
dec = 2 + np.random.randn(262615)
print(np.shape(dec))
ra = 150 + np.random.randn(262615)
print(np.shape(ra))
c = np.zeros(262615)
print(np.shape(c))
for i in range(262615):
c[i] = SkyCoord(ra=ra[i]*u.degree,dec=dec[i]*u.degree,distance=R[i]*u.mpc)
print(c[i])
这是我的错误消息:
PS C:\Users\sirep\Documents\C++ scripts> cd 'c:\Users\sirep\Documents\C++ scripts'; ${env:PYTHONIOENCODING}='UTF-8'; ${env:PYTHONUNBUFFERED}='1'; & 'C:\Users\sirep\Anaconda3\python.exe' 'c:\Users\sirep\.vscode\extensions\ms-python.python-2018.5.0\pythonFiles\PythonTools\visualstudio_py_launcher.py' 'c:\Users\sirep\Documents\C++ scripts' '57764' '34806ad9-833a-4524-8cd6-18ca4aa74f14' 'RedirectOutput,RedirectOutput' 'c:\Users\sirep\Documents\Python Scripts\sph2cart.py'
(262615,)
(262615,)
(262615,)
(262615,)
Traceback (most recent call last):
File "c:\Users\sirep\Documents\Python Scripts\sph2cart.py", line 16, in <module>
c[i] = SkyCoord(ra=ra[i]*u.degree,dec=dec[i]*u.degree,distance=R[i]*u.mpc)
ValueError: setting an array element with a sequence.
谢谢大家的光临!
答案 0 :(得分:1)
我认为我应该将comment扩展为更长的答案,因为这里有些事情值得将来的读者解释和澄清。
您在your answer中写道:
我发现了我的错误。 SkyCoord返回x坐标,y坐标和z坐标的3个值。我试图将三个值分配给数组的单个元素。
这当然是正确的,但并不完全正确。在您的原始代码中,您有类似以下内容:
c = np.zeros(262615)
这已经有点麻烦了,因为您没有指定数据类型,但是默认情况下,数据类型为float64
,这可能是许多应用程序想要的(肯定适用于此应用程序)。在任何情况下,键入Numpy数组都意味着,如果像原始代码中那样分配给数组的单个元素:
c[i] = SkyCoord(ra=ra[i]*u.degree,dec=dec[i]*u.degree,distance=R[i]*u.mpc)
您所分配的值最好是浮点数,或者至少是可以明确转换为浮点数的其他一些数字类型(例如int
)。对于SkyCoord
而言,这是不正确的,因为您已经注意到,它是三个维度的倍数。我的意思是,通常,如果您使用的是Numpy数组,则要注意它的dtype
是什么以及要分配给它的元素的内容。对于更多任意对象,您更有可能会得到更清晰的错误,例如:
>>> c[0] = object()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: float() argument must be a string or a number
仍然不是很好,但是至少表明它正在尝试调用float()
将参数转换为浮点数。但是对于SkyCoord
,您会得到不同的结果,因为SkyCoord
可以是包含许多坐标的数组的容器,Numpy看到了这一点,而是尝试将其视为将值序列分配给标量,这是您得到的错误。
顺便说一句,在Numpy中也可以使用structured arrays创建更复杂的数组类型。这允许您创建(x, y, z)
坐标数组,例如:
>>> c = np.zeros(262615, dtype=[('x', 'f8'), ('y', 'f8'), ('z', 'f8')])
>>> c
array([(0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), ...,
(0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0)],
dtype=[('x', '<f8'), ('y', '<f8'), ('z', '<f8')])
>>> c[0]
(0.0, 0.0, 0.0)
尽管您不能直接将SkyCoord
分配给这些值之一(从技术上讲,我认为SkyCoord
被视为无坐标的,而不管您实例化了哪个坐标系,但是我可能是错误的),您可以分配例如:
>>> c[0] = SkyCoord(ra=ra[i]*u.degree,dec=dec[i]*u.degree,distance=R[i]*u.mpc).cartesian.xyz
但是,仍然没有必要,因为正如我在评论中提到并进一步解释in the docs,SkyCoord
可以表示像这样的坐标数组:
>>> coords = SkyCoord(ra=ra*u.degree, dec=dec*u.degree, distance=R*u.mpc)
您可以将其全部转换为笛卡尔坐标,并为x,y和z坐标检索单独的数组,例如:
>>> x, y, z = coords.cartesian.xyz
这还有一个额外的优势,即使用最合适的长度尺寸({Mcpc,因为这就是您输入的距离),坐标以Quantity
的形式返回。但是,coords.cartesian
本身实际上已经是(x, y, z)
坐标的数组,就像上面的结构化数组示例一样(从技术上讲,它不是Numpy数组,但是它具有许多相同的方法,可以转换为一个喜欢):
>>> coords.cartesian._values
array([(0.19718680211339326, 0.002173755110841713, 0.0021735811221131776),
(0.6853033697941637, 0.005924402286034272, 0.004262079913938389),
...
dtype=[('x', '<f8'), ('y', '<f8'), ('z', '<f8')])
但是这是一个不公开的内部属性,不应该使用(尽管我不确定为什么不公开此接口,因为它可能有用...)
最后,我将添加一个使用此接口的方法,它的速度要快得多,因为所有循环都是在C中进行矢量化数组操作的。任何时候,您在Python级别执行操作,例如分配给数组({{1 }}或属性访问(c[i] = ...
)会导致性能下降,因为需要将值从C转换为Python,然后再次转换回C。使用向量化操作可以避免所有这些情况。因此,当我制作一个c.cartesian.x.value
数组时,我得到:
SkyCoord
对于In [7]: %%timeit
...: c = SkyCoord(ra=ra*u.degree, dec=dec*u.degree, distance=R*u.mpc)
...: c.cartesian.xyz
...:
10 loops, best of 3: 111 ms per loop
坐标,为或111ms,如原始示例中所示。而“天真”的方式会让我:
262615
答案 1 :(得分:0)
我发现了我的错误。 SkyCoord返回x坐标,y坐标和z坐标的3个值。我试图将三个值分配给数组的单个元素。要解决此问题,我必须首先为每个坐标创建3个单独的数组,然后确保在输入各自的数组时每个值都是无量纲的:
from astropy.coordinates import SkyCoord
from astropy import units as u
import numpy as np
R = 445 + np.random.randn(262615)
print(np.shape(R))
dec = 2 + np.random.randn(262615)
print(np.shape(dec))
ra = 150 + np.random.randn(262615)
print(np.shape(ra))
cx = np.zeros(262615)
cy = np.zeros(262615)
cz = np.zeros(262615)
print(np.shape(cx))
for i in range(262):
c = SkyCoord(ra=ra[i]*u.degree,dec=dec[i]*u.degree,distance=R[i]*u.mpc)
cx[i] = c.cartesian.x.value
cy[i] = c.cartesian.y.value
cz[i] = c.cartesian.z.value
print(cx[i],cy[i],cz[i])