Вы пытаетесь создать представление в массиве с несовместимым макетом памяти, где вывод dtype
имеет itemsize , который не полностью соответствует количеству байтов, необходимых в памяти для покрытия полная длина «последней» оси исходного массива. Исключение также будет применяться, если вы просто устанавливаете атрибут .dtype
для массива напрямую , а не просто для ndarray.view()
(который создает новый ndarray
с dtype
, установленным для этого нового объекта) .
Здесь «последняя» ось является «самым внутренним» измерением с точки зрения структуры памяти ; для массивов C-порядка это shape[-1]
, для массивов Фортрана это shape[0]
. Этот размерный размер, умноженный на исходный dtype.itemsize
, должен делиться на новый dtype.itemsize
, иначе вы не сможете просто «пройтись» по структуре внутренней памяти.
Например, для массива C-порядка (основного порядка строк) с формой (4, 3, 5)
и dtype.itemsize
из 8, «последняя» ось занимает 5 * 8 == 40 байт памяти и т. Д. Вы можете создать представление для этого с большими dtypes размеров 10, 20 и 40. Тот же массив, но в порядке Fortran (порядок столбцов), однако, использует 4 * 8 == 32 байта памяти , ограничивая ваши варианты только большими dtypes размеров 16 и 32.
Если X.view([('', X.dtype)] * X.shape[1])
терпит неудачу, то либо X.shape
имеет больше измерений, чем просто 2, или , это массив с использованием Fortran-упорядочения. Вы можете исправить первое с помощью X.shape[-1]
, и вы можете проверить последние, просмотрев ndarray.flags['F_CONTIGUOUS']
. Объединение их в одно выражение, подобное следующему, должно работать:
X_rows = X.view([('', X.dtype)] * X.shape[0 if X.flags['F_CONTIGUOUS'] else -1])
Однако , поскольку документация ndarray.view()
предупреждает:
Представления, изменяющие размер dtype
(байт на запись), обычно следует избегать для массивов, определяемых срезами, транспонированием, упорядочением по фортрану и т. Д. [.]
Когда вы пытаетесь изменить dtype массива порядка Фортрана, появляется предупреждение:
DeprecationWarning: Changing the shape of an F-contiguous array by descriptor assignment is deprecated. To maintain the Fortran contiguity of a multidimensional Fortran array, use 'a.T.view(...).T' instead
так что было бы лучше транспонировать массив, создать ваше представление, а затем снова транспонировать полученное представление:
if X.flags['F_CONTIGUOUS']:
X_rows = X.T.view([('', X.dtype)] * X.shape[0]).T
Вам все еще нужно придерживаться X.shape[0]
здесь, это shape[-1]
транспонированного массива.
Тот факт, что поддержка изменения dtype
в массивах порядка Фортрана устарела, также может объяснить ссылку исключения на «последнюю ось», что совершенно естественно с точки зрения массивов C-порядка, но кажется нелогичным, когда применяется к массивам фортрановских порядков.
Я даже не вижу, какой исходный код .py выдает эту ошибку.
Numpy в основном написан на C (с чертой на Fortran 77), поэтому вам нужно покопаться в исходном коде скомпилированных компонентов. Ошибка генерируется в функции установки дескриптора дескриптора dtype
, которая здесь вызывается, когда функция PyArray_View()
вызывает функцию PyObject_SetAttrString()
для установки атрибута dtype
, когда она вызывается из ndarray.view()
метода .
Согласно исходному коду, не только изменение dtype массивов порядка Фортрана устарело, но и представления несмежных массивов вообще не поддерживаются (это означает, что если X.flags['C_CONTIGUOUS']
и X.flags['F_CONTIGUOUS']
равны False
тогда вы вообще не сможете изменить dtype
.