Почему `numpy.ndarray.view` игнорирует предыдущий вызов` numpy.ndarray.newbyteorder`? - PullRequest
0 голосов
/ 21 мая 2018

У меня есть массив NumPy с одним элементом типа данных uint32:

>>> import numpy as np
>>> a = np.array([123456789], dtype=np.uint32)
>>> a.dtype.byteorder
'='

Затем я могу выбрать интерпретацию данных как младший:

>>> a.newbyteorder("<").dtype.byteorder
'<'
>>> a.newbyteorder("<")
array([123456789], dtype=uint32)

Или с прямым порядком байтов:

>>> a.newbyteorder(">").dtype.byteorder
'>'
>>> a.newbyteorder(">")
array([365779719], dtype=uint32)

Где последний возвращает другое число 365779719, поскольку моя платформа имеет младший порядок байтов - и, следовательно, записана в память в порядке младших порядков.

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

>>> a.newbyteorder("<").view(np.uint8)
array([ 21, 205,  91,   7], dtype=uint8)
>>> a.newbyteorder(">").view(np.uint8)
array([ 21, 205,  91,   7], dtype=uint8)

Я бы ожидал, что числа будут наоборотдля байтового порядка с прямым порядком байтов.Почему этого не происходит?Разве view не просматривает данные "через" метод newbyteorder?

Кстати: если я использую byteswap вместо newbyteorder и, следовательно, копирую и изменяю байты в памяти,Я, очевидно, получаю желаемый результат:

>>> a.byteswap("<").view(np.uint8)
array([ 21, 205,  91,   7], dtype=uint8)
>>> a.byteswap(">").view(np.uint8)
array([  7,  91, 205,  21], dtype=uint8)

Однако я не хочу копировать данные.

Ответы [ 3 ]

0 голосов
/ 21 мая 2018

Просто добавьте к @ user2357112 ответ , из документации :

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

  • Измените информацию о порядке байтов в массиве dtype, чтобы он интерпретировал базовые данные как находящиеся вдругой порядок байтов .Это роль arr.newbyteorder()
  • Изменить порядок байтов базовых данных , оставив интерпретацию dtype такой, какой она была.Это то, что arr.byteswap() делает.

Мой акцент в приведенной выше цитате.


Другие мысли, собранные из комментариев:

Начиная с newbyteorder() аналогичен view () в том смысле, что он просто изменяет интерпретацию базовых данных без изменения данных; создается впечатление, что представление в представлении - это представление тех же (исходных) данных.Так что, да, вы не можете «цеплять» представления (ну, вы можете ... но это всегда представление для одних и тех же исходных данных).

Как получить uint8 чанки в порядке с прямым порядком байтов без изменения памяти, тогда?

Попробуйте np.sum(a.newbyteorder('<')) (или попробуйте a.newbyteorder('<').tolist()), а также измените знак / порядок байтов.Итак, мой ответ на поставленный выше вопрос заключается в том, что вы не можете сделать это: либо память изменяется «на месте» с помощью byteswap(), либо путем копирования данных в новую ячейку памяти при доступе к элементам ввид.

0 голосов
/ 23 мая 2018
In [280]: a = np.array([123456789, 234567891, 345678912], dtype=np.uint32)

In [282]: a.tobytes()
Out[282]: b'\x15\xcd[\x07\xd38\xfb\r@\xa4\x9a\x14'

In [284]: a.view('uint8')
Out[284]: 
array([ 21, 205,  91,   7, 211,  56, 251,  13,  64, 164, 154,  20],
      dtype=uint8)

Это то же самое, что и a.view('<u1') и a.view('>u1'), так как конечность не имеет значения с одиночными байтами.

In [291]: a.view('<u4')
Out[291]: array([123456789, 234567891, 345678912], dtype=uint32)
In [292]: a.view('>u4')
Out[292]: array([ 365779719, 3543726861, 1084529172], dtype=uint32)

Представление полностью зависит от данных, а не от текущего (last) view:

In [293]: a.view('<u4').view('u1')
Out[293]: 
array([ 21, 205,  91,   7, 211,  56, 251,  13,  64, 164, 154,  20],
      dtype=uint8)
In [294]: a.view('>u4').view('u1')
Out[294]: 
array([ 21, 205,  91,   7, 211,  56, 251,  13,  64, 164, 154,  20],
      dtype=uint8)

Об идее изменения формы и обращения:

In [295]: a.view('u1').reshape(-1,4)
Out[295]: 
array([[ 21, 205,  91,   7],
       [211,  56, 251,  13],
       [ 64, 164, 154,  20]], dtype=uint8)
In [296]: a.view('u1').reshape(-1,4)[:,::-1]
Out[296]: 
array([[  7,  91, 205,  21],
       [ 13, 251,  56, 211],
       [ 20, 154, 164,  64]], dtype=uint8)

Но я не могу изменить представление (на u4) этого массива, потому что он неНе смежно:

In [297]: a.view('u1').reshape(-1,4)[:,::-1].view('<u4')
....
ValueError: To change to a dtype of a different size, the array must be C-contiguous

Посмотрите немного подробнее о свойствах этого обращенного массива:

In [298]: a1 = a.view('u1').reshape(-1,4)[:,::-1]
In [299]: a1.flags
Out[299]: 
  C_CONTIGUOUS : False
  F_CONTIGUOUS : False
  ....
In [300]: a1.strides             # reversing is done with strides
Out[300]: (4, -1)

2 массива совместно используют один и тот же буфер данных.a2 просто начинается с другого байта:

In [301]: a.__array_interface__['data']
Out[301]: (32659520, False)
In [302]: a1.__array_interface__['data']
Out[302]: (32659523, False)

Я не могу сделать изменение формы на месте a1:

In [304]: a1.shape = (12,)
...
AttributeError: incompatible shape for a non-contiguous array

Если я сделаю reshape,Я получаю копию (как показано по совершенно другому адресу буфера данных):

In [305]: a2 = a1.reshape(-1)
In [306]: a2
Out[306]: 
array([  7,  91, 205,  21,  13, 251,  56, 211,  20, 154, 164,  64],
      dtype=uint8)
In [307]: a2.view('<u4')
Out[307]: array([ 365779719, 3543726861, 1084529172], dtype=uint32)
In [308]: a2.__array_interface__['data']
Out[308]: (37940512, False)

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


newbyteorder документы говорят, что это эквивалентно:

arr.view(arr.dtype.newbytorder(new_order))

Так что a.view('<u4').newbyteorder('>') совпадает с a.view('<u4'),Ни одно из этих изменений a.

0 голосов
/ 21 мая 2018

Новый порядок байтов, примененный с newbyteorder, является исключительно свойством массива dtype;a.newbyteorder("<") возвращает представление a с прямым порядком байтов dtype.Он не изменяет содержимое памяти и не влияет на форму или шаг массива.

ndarray.view не заботится о dtype исходного массива, порядке с прямым порядком байтов или большом.Он заботится о форме массива, шагах и фактическом содержании памяти, ни один из которых не изменился.

...