Ошибка числового значения: установка элемента массива с последовательностью - PullRequest
0 голосов
/ 26 июня 2018

Я пишу код на Python, используя numpy и astropy. В коде я хочу создать случайные массивы, которые обычно напоминают мои наборы данных. После этого я хотел бы преобразовать эти рандомизированные массивы сферических координат в декартовы. К сожалению, я продолжаю получать ошибку значения, я полностью озадачен тем, почему это происходит, я пытался сделать несколько фиктивных тестов, таких как, если они имеют одинаковую форму, все массивы имеют разумные значения и того же типа и т. Д., Но Я застрял. вот мой код:

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.

Спасибо всем за потраченное время!

Ответы [ 2 ]

0 голосов
/ 27 июня 2018

Я подумал, что должен расширить свой комментарий на более длинный ответ, поскольку некоторые вещи здесь заслуживают объяснения и разъяснения для будущих читателей.

В ваш ответ Вы написали:

Я понял свою ошибку. SkyCoord возвращает 3 значения координаты x, координаты y и координаты z. Я пытался присвоить три значения одному элементу массива.

и это, конечно, на правильном пути, но не совсем. В исходном коде у вас было что-то вроде:

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 также возможно создавать более сложные типы массивов, используя структурированные массивы . Это позволяет вам создать массив (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

Однако в этом все еще нет необходимости, потому что, как я упоминал в своем комментарии и объяснял далее, в документации a SkyCoord может представлять массив координат, например:

>>> coords = SkyCoord(ra=ra*u.degree, dec=dec*u.degree, distance=R*u.mpc)

и вы можете преобразовать все это за один раз в декартовы координаты и получить отдельные массивы для координат x, y и z, например:

>>> x, y, z = coords.cartesian.xyz

Это дает дополнительное преимущество: координаты возвращаются как Quantity s с использованием наиболее подходящего измерения длины (в данном случае Мпк, поскольку это то, что вы указали в своих расстояниях). Однако сам по себе 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

или 111ms для 262615 координат, как в исходном примере. Принимая во внимание, что «наивный» путь заставляет меня:

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
0 голосов
/ 26 июня 2018

Я понял свою ошибку. SkyCoord возвращает 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])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...