Numpy Value Error: setting an array element with a sequence

Numpy Value Error: setting an array element with a sequence

我正在 Python 使用 numpy 和 astropy 编写代码。在代码中,我希望创建通常类似于我的数据集的随机 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.

谢谢大家的宝贵时间!

我发现了我的错误。 SkyCoord returns 3 值 x 坐标、y 坐标和 z 坐标。我试图将三个值分配给数组的单个元素。为了解决这个问题,我必须首先为每个坐标创建 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])

我认为我应该将我的 扩展为更长的答案,因为这里的一些事情值得为未来的读者解释和澄清。

你写道:

I've figured out my error. SkyCoord returns 3 values an x coordinate, y coordinate and z coordinate. I was trying to assign three values to a single element of an array.

这肯定是在正确的轨道上,但不完全正确。在您的原始代码中,您有类似的内容:

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

这有一个额外的好处,即使用最合适的长度维度(在本例中为 Mpc,因为这是您给出的距离),坐标作为 Quantitys 返回。但是,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 级别做事情,比如分配给数组 (c[i] = ...) 或属性访问 (c.cartesian.x.value) 您会招致严重的性能损失,因为值需要从 C 转换为 Python 并再次转换回 C。使用矢量化操作可以避免这一切。所以当我制作一个 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

262615 坐标为 111 毫秒,如您的原始示例所示。而 "naïve" 的方式让我得到:

In [11]: %%timeit
    ...: for i in range(262615):
    ...:     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
    ...:

1 loop, best of 3: 18min 26s per loop