Создание экземпляра скаляра пользовательского структурированного dtype

#python #numpy

#python #numpy #скаляр

Вопрос:

Я определил пользовательский dtype. Например:

 vec = np.dtype([('x', float), ('y', float), ('z', float)])
quat = np.dtype([('w', float), ('v', vec)])
 

Теперь я хочу создать скалярный кватернион:

 quat((1.0, (0.0, 0.0, 0.0)))
 

Я ожидал бы, что, во всяком случае, мой синтаксис кортежей неприемлем. Однако вместо этого я получаю следующую ошибку:

 TypeError: 'numpy.dtype' object is not callable
 

Соответствующая часть документации по скалярам подразумевает, что возможно иметь скаляр структурированного типа, построенный подобным образом в numpy.

Как создать экземпляр quat скаляра? Возможно ли это вообще?

Кстати, я поиграл со следующим обходным путем:

 np.array([(1.0, (0.0, 0.0, 0.0))], dtype=quat)
 

Это не создает фактического скаляра (хотя, честно говоря, он работает достаточно хорошо для моих целей, что делает вопрос в основном теоретическим). Вызов item результата возвращает a tuple , а не скалярный quat объект.

Комментарии:

1. Хотя int и np.float32 может действовать как dtype и функции для создания скаляра numpy, я не думаю np.dtype , что экземпляр может это сделать. У него нет __call__ метода (проверьте это).

2. Составной dtype создает np.void объект. (или для recarray a np.record )

3. @hpaulj. Я полностью согласен. Но, похоже, в документах есть какой -то способ. Я полагаю, если кто-нибудь знает, это будешь ты, Дивакар или около того.

4. @hpaulj. Так я и пытался сделать quat.type(pack('dddd', 1.0, 0.0, 0.0, 0.0)) . Вероятно, это шаг в правильном направлении, но не совсем полезный в его необработанном виде

5. @hpaulj. Понял: quat.type(pack('dddd', 1.0, 0.0, 0.0, 0.0)).view(quat)

Ответ №1:

Вызов item вашего массива привел к созданию кортежа, поскольку item он специально разработан для преобразования типов NumPy в типы Python. Индексирование массива создает скаляр типа NumPy numpy.void :

 scalar = np.array([(1.0, (0.0, 0.0, 0.0))], dtype=quat)[0]
 

Комментарии:

1. Это действительно намного чище, чем моя версия. Спасибо.

Ответ №2:

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

Тип quat np.void :

 >>> quat.type
numpy.void
 

Поскольку это общий набор для пользовательских типов, он должен быть создан с помощью байтоподобного объекта:

 >>> from struct import pack
>>> q = quat.type(pack('dddd', 1.0, 0.0, 0.0, 0.0))
>>> q
void(b'x00x00x00x00x00x00xF0x3Fx00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00')
 

И, конечно, поскольку это универсальный универсальный инструмент, вам нужно указать ему, как интерпретировать себя. К счастью, у скаляров также есть view метод:

 >>> q = q.view(quat)
>>> q
(1., (0., 0., 0.))
>>> q.dtype
dtype([('w', '<f8'), ('v', [('x', '<f8'), ('y', '<f8'), ('z', '<f8')])])
 

TL; DR

 q = np.void(pack('dddd', 1.0, 0.0, 0.0, 0.0)).view(quat)