Из поваренной книги SciPy :
Основное правило для создания вида среза заключается в том, что к просматриваемым элементам можно обращаться со смещениями, шагами и количеством в оригинале.массив.
Когда у вас есть индексирование, подобное x[[1, slice(None), 2]]
, вы получаете представление, потому что разрезание по всей оси допускает определенное смещение, шаг и счет для представления среза с исходным массивом.
Например, с x = np.arange(27).reshape(3, 3, 3).copy()
мы имеем:
In [79]: x_view = x[1, :, 2] # or equivalently x[[1, slice(None), 2]]
In [80]: x_view
Out[80]: array([11, 14, 17])
In [81]: x_view.base
Out[81]:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]],
[[18, 19, 20],
[21, 22, 23],
[24, 25, 26]]])
Тогда мы можем использовать numpy.byte_bounds
(не является частью публичного API, YMMV) дляпроиллюстрируем смещение, чтобы получить наш фрагмент из нашего исходного массива.
In [82]: np.byte_bounds(x_view)[0] - np.byte_bounds(x_view.base)[0]
Out[82]: 88
Это имеет смысл, поскольку перед первым значением в срезе стоят 11 8-байтовых целых чисел, 11. NumPy вычисляет это смещение по формуле, которую вы можете см. Здесь , используяшаги исходного массива.
In [93]: (x.strides * np.array([1, 0, 2])).sum()
Out[93]: 88
Шаги в нашем срезе просто становятся такими, какими были шаги для x
вдоль оси (или осей), на которой мы нарезаем.то есть x.strides[1] == x_view.strides[0]
.Теперь вместе смещение, новые шаги и количество являются достаточной информацией для NumPy, чтобы просмотреть наш срез из нашего исходного массива.
In [94]: x_view.strides
Out[94]: (24,)
In [95]: x_view.size
Out[95]: 3
Наконец, причина, по которой вы запускаете необычное индексирование, например, с помощью x[[0, 1, 2]]
, заключается в том, что в отсутствие полного среза оси, как правило, невозможно сформулировать какое-либо новое смещение, порядок байтов,шагает и считает так, что мы можем просматривать срез с теми же базовыми данными.