Numpy рассматривает смежную часть несмежного массива как dtype большего размера - PullRequest
0 голосов
/ 14 ноября 2018

Я пытался сгенерировать массив триграмм (то есть непрерывных трехбуквенных комбинаций) из сверхдлинного массива символов:

# data is actually load from a source file
a = np.random.randint(0, 256, 2**28, 'B').view('c')

Поскольку копирование неэффективно (и это создает такие проблемы, как кэшпропустил), я непосредственно сгенерировал триграмму, используя трюки шага:

tri = np.lib.stride_tricks.as_strided(a, (len(a)-2,3), a.strides*2)

Это создает список триграмм с формой (2**28-2, 3), где каждая строка - триграмма.Теперь я хочу преобразовать триграмму в список строк (т.е. S3), чтобы numpy отображал ее более «разумно» (вместо отдельных символов).

tri = tri.view('S3')

Это дает исключение:

ValueError: To change to a dtype of a different size, the array must be C-contiguous

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

Итак, я 'Интересно как view смежных частей в несмежных np.ndarray как dtype большего размера ?Более «стандартный» способ был бы лучше, хотя хакерские способы также приветствуются.Кажется, что я могу свободно установить shape и stride с помощью np.lib.stride_tricks.as_strided, но я не могу заставить dtype быть чем-то, что является проблемой здесь.

EDIT

Несмежный массив может быть сделан простой нарезкой.Например:

np.empty((8, 4), 'uint32')[:, :2].view('uint64')

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

1 Ответ

0 голосов
/ 14 ноября 2018

Если у вас есть доступ к непрерывному массиву, из которого получен ваш несмежный массив, обычно должно быть возможно обойти это ограничение.

Например, ваши триграммы могут быть получены так:

>>> a = np.random.randint(0, 256, 2**28, 'B').view('c')
>>> a
array([b')', b'\xf2', b'\xf7', ..., b'\xf4', b'\xf1', b'z'], dtype='|S1')
>>> np.lib.stride_tricks.as_strided(a[:0].view('S3'), ((2**28)-2,), (1,))
array([b')\xf2\xf7', b'\xf2\xf7\x14', b'\xf7\x14\x1b', ...,
       b'\xc9\x14\xf4', b'\x14\xf4\xf1', b'\xf4\xf1z'], dtype='|S3')

Фактически, этот пример демонстрирует, что все, что нам нужно, - это непрерывная «заглушка» в основании буфера памяти для приведения к просмотру, поскольку впоследствии, поскольку as_strided не делает много проверок, мы, по сути, свободны делатьвсе, что нам нравится.

Кажется, что мы всегда можем получить такую ​​заглушку, нарезав массив размером 0.Для вашего второго примера:

>>> X = np.empty((8, 4), 'uint32')[:, :2]
>>> np.lib.stride_tricks.as_strided(X[:0].view(np.uint64), (8, 1), X.strides)
array([[140133325248280],
       [             32],
       [       32083728],
       [       31978800],
       [              0],
       [       29686448],
       [             32],
       [       32362720]], dtype=uint64)
...