{"id":14291,"url":"\/distributions\/14291\/click?bit=1&hash=257d5375fbb462be671b713a7a4184bd5d4f9c6ce46e0d204104db0e88eadadd","hash":"257d5375fbb462be671b713a7a4184bd5d4f9c6ce46e0d204104db0e88eadadd","title":"\u0420\u0435\u043a\u043b\u0430\u043c\u0430 \u043d\u0430 Ozon \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u0442\u0430\u043c \u043d\u0435 \u043f\u0440\u043e\u0434\u0430\u0451\u0442","buttonText":"","imageUuid":""}

Продвинутый NumPy: оттачивайте навыки с помощью 25 иллюстрированных упражнений

В этой статье мы рассмотрим 25 различных упражнений, используя библиотеку NumPy (и сравним с тем, как мы бы реализовали их без неё).

Для этой статьи рекомендуется, чтобы читатель имел средний уровень знаний Python, NumPy, numpy.dtype, numpy.ndarray.strides, и numpy.ndarray.itemsize. Краткое введение в массивы и шаги NumPy см. в разделе 💡 Немного предыстории ниже.

Упражнения расположены по возрастающей сложности. Вот структура каждого из упражнений:

  • Вопрос, показанный в виде диаграммы с вводом массива NumPy
  • Ответ
  • Объяснение
  • Код, в котором присутствует пространство имён as_strided, импортированное из следующего оператора импорта:from numpy.lib.stride_tricks import as_strided

💡 Немного предысторииКак получить доступ к конкретному элементу из блока элементов фиксированного размера, которые (i) размещены рядом друг с другом и (ii) организованы во вложенные подгруппы? Ответ: с помощью шагов. То, что я только что кратко описал, — это N-мерный массив структуры данных NumPy ( ndarray), и мы используем алгоритм, называемый схемой пошагового индексирования , вместе с шагами для её обхода.Вот 4 коротких момента, которые вы должны знать о массивах NumPy:1) Элементы в массивах NumPy занимают память. Каждый элемент в массиве NumPy равномерно занимает n байтов. Например, каждый элемент массива с типом данных np.int64 занимает 8 байт.2) Элементы в массивах NumPy хранятся в памяти непрерывно. Это означает, что они хранятся рядом (в отличие от элементов в списках Python).3) Существует часть информации, называемая формой, которую вы, вероятно, уже знаете, которая определяет, насколько велик этот массив для каждого измерения.4) Существует ещё одна часть информации, называемая шагами, которая указывает количество байтов, на которое нужно перейти, чтобы достичь следующего значения в измерении.С помощью этих 4 частей информации местоположение элемента в памяти можно найти с помощью линейной комбинации измерения с шагами в качестве коэффициентов. Для более подробного объяснения обратитесь к моим ссылкам ниже .

1D упражнения

1) Нарезка первых 3 элементов

Ответ

strides = (1,) shape = (3,)

💡 Объяснение Смежные элементы в выходных данных (т. е. 1 → 2, 2 → 3) изначально находились на расстоянии 1 байта друг от друга (= 1 элемент на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 3 .

Код

>>> x = np.asarray(range(1,26), np.int8).reshape(5,5) >>> as_strided(x, shape=(3,), strides=(1,)) array([1, 2, 3], dtype=int8)

Сравнение

>>> x[0,:3] array([1, 2, 3], dtype=int8)

2) Нарезка первых 8 элементов

Ответ
strides = (1,) shape = (8,)

💡 Объяснение Смежные элементы в выходных данных (например, 1 → 2, 2 → 3, 6 → 7) изначально находились на расстоянии 1 байта друг от друга (= 1 элемент на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 8 .

Код

>>> x = np.asarray(range(1,26), np.int8).reshape(5,5) >>> as_strided(x, shape=(8,), strides=(1,)) array([1, 2, 3, 4, 5, 6, 7, 8], dtype=int8)

Сравнение

>>> x[0,:8] array([1, 2, 3, 4, 5, 6, 7, 8], dtype=int8)

3) Сглаживание двумерного массива

Ответ

strides = (2,) shape = (25,)

💡 Объяснение Смежные элементы на выходе (например, 1 → 2, 2 → 3, 23 → 24, 24 → 25) изначально находились на расстоянии 2 байта друг от друга (= 1 элемент на расстоянии × 2 байта) на входе. Форма этого измерения равна 25 .

Код

>>> x = np.asarray(range(1,26), np.int16).reshape(5,5) >>> as_strided(x, shape=(25,), strides=(2,)) array([ 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], dtype=int16)

Сравнение

>>> x.ravel() array([ 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], dtype=int16)

4) Пропуск всех остальных элементов

Ответ

strides = (2,) shape = (3,)

💡 Объяснение Смежные элементы в выходных данных (т.е. 1 → 3, 3 → 5) изначально находились на расстоянии 2 байта друг от друга (= 2 элемента на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 3 .

Код

>>> x = np.asarray(range(1,26), np.int8).reshape(5,5) >>> as_strided(x, shape=(3,), strides=(2,)) array([1, 3, 5], dtype=int8)

Сравнение

>>> x[0,::2] array([1, 3, 5], dtype=int8)

5) Нарезка первого столбца

Ответ

strides = (40,) shape = (4,)

💡 Объяснение Смежные элементы в выходных данных (т. е. 1 → 6, 6 → 11, 11 → 16) изначально находились на расстоянии 40 байт друг от друга (= 5 элементов на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 4 .

Код

>>> x = np.asarray(range(1,26), np.int64).reshape(5,5) >>> as_strided(x, shape=(4,), strides=(40,)) array([ 1, 6, 11, 16])

Сравнение

>>> x[:4,0] array([ 1, 6, 11, 16])

6) Нарезка по диагонали

Ответ

strides = (48,) shape = ( 5,)

💡 Объяснение Смежные элементы в выходных данных (т. е. 1 → 7, 7 → 13, 13 → 19, 19 → 25) изначально находились на расстоянии 48 байт друг от друга (= 6 элементов на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 5 .

Код

>>> x = np.asarray(range(1,26), np.int64).reshape(5,5) >>> as_strided(x, shape=(5,), strides=(48,)) array([ 1, 7, 13, 19, 25])

Сравнение

>>> x.diagonal() array([ 1, 7, 13, 19, 25])

7) Повторение первого элемента

Ответ

strides = (0,) shape = (5,)

💡 Объяснение Смежные элементы в выходных данных (т. е. 1 → 1) изначально находились на расстоянии 0 байтов друг от друга (= 0 элементов на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 5 .

Код

>>> x = np.asarray(range(1,26), np.int64).reshape(5,5) >>> as_strided(x, shape=(5,), strides=(0,)) array([ 1, 1, 1, 1, 1])

Сравнение

>>> np.broadcast_to(x[0,0], (5,)) array([1, 1, 1, 1, 1])

2D упражнения

8) Простая 2D-нарезка

Ответ

strides = (40,8) shape = ( 3,4)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 2, 2 → 3, 8 → 9) изначально находились на расстоянии 8 байтов друг от друга (= 1 элемент на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 4 .Выходное измерение слева направо (ось = -2):Смежные элементы на выходе (например, 1 → 6, 2 → 7, 9 → 14) изначально находились на расстоянии 40 байт друг от друга (= 5 элементов на расстоянии × 8 байтов) на входе. Форма этого измерения равна 3 .

Код

>>> x = np.asarray(range(1,26), np.int64).reshape(5,5) >>> as_strided(x, shape=(3,4), strides=(40,8)) array([[ 1, 2, 3, 4], [ 6, 7, 8, 9], [11, 12, 13, 14]])

Сравнение

>>> x[:3,:4] array([[ 1, 2, 3, 4], [ 6, 7, 8, 9], [11, 12, 13, 14]])

9) Нарезка зигзагом

Ответ

strides = (48,8) shape = ( 4,2)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Смежные элементы на выходе (например, 1 → 2, 7 → 8, 13 → 14, 19 → 20) изначально находились на расстоянии 8 байтов друг от друга (= 1 элемент на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 2 .Выходное измерение слева направо (ось = -2):Смежные элементы на выходе (например, 1 → 7, 2 → 8, 13 → 19) изначально находились на расстоянии 48 байт друг от друга (= 6 элементов на расстоянии × 8 байтов) на входе. Форма этого измерения равна 4 .

Код

>>> x = np.asarray(range(1,26), np.int64).reshape(5,5) >>> as_strided(x, shape=(4,2), strides=(48,8)) array([[ 1, 2], [ 7, 8], [13, 14], [19, 20]])

Сравнение

>>> # this may not be achieved concisely

10) Разреженная нарезка

Ответ

strides = (80,16) shape = ( 3, 3)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 3, 21 → 23, 13 → 15) изначально находились на расстоянии 16 байт друг от друга (= 2 элемента на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 3 .Выходное измерение слева направо (ось = -2):Смежные элементы в выходных данных (например, 1 → 11, 13 → 23, 15 → 25) изначально находились на расстоянии 80 байт друг от друга (= 10 элементов на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 3 .

Код

>>> x = np.asarray(range(1,26), np.int64).reshape(5,5) >>> as_strided(x, shape=(3,3), strides=(80,16)) array([[ 1, 3, 5], [11, 13, 15], [21, 23, 25]])

Сравнение

>>> x[::2,::2] array([[ 1, 3, 5], [11, 13, 15], [21, 23, 25]])

11) Транспонирование 2D-массива

Ответ

strides = (1,5) shape = (3,3)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 6, 7 → 12, 3 → 8) изначально находились на расстоянии 5 байтов друг от друга (= 5 элементов на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 3 .Размер вывода сверху направо (ось = -2):Смежные элементы в выходных данных (например, 1 → 2, 2 → 3, 11 → 12) изначально находились на расстоянии 1 байта (= 1 элемент на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 3 .

Код

>>> x = np.asarray(range(1,26), np.int8).reshape(5,5) >>> as_strided(x, shape=(3,3), strides=(1,5)) array([[ 1, 6, 11], [ 2, 7, 12], [ 3, 8, 13]], dtype=int8)

Сравнение

>>> x[:3,:3].T array([[ 1, 6, 11], [ 2, 7, 12], [ 3, 8, 13]], dtype=int8)

12) Повтор первого столбца 4 раза

Ответ

strides = (20,0) shape = ( 5,4)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 1, 6 → 6, 16 → 16) изначально находились на расстоянии 0 байтов друг от друга (= 0 элементов на расстоянии × 4 байта) во входных данных. Форма этого измерения равна 4 .Выходное измерение сверху вниз (ось = -2):Смежные элементы на выходе (например, 1 → 6, 6 → 11, 11 → 16) изначально находились на расстоянии 20 байт друг от друга (= 5 элементов на расстоянии × 4 байта) на входе. Форма этого измерения равна 5 .

Код

>>> x = np.asarray(range(1,26), np.int32).reshape(5,5) >>> as_strided(x, shape=(5,4), strides=(20,0)) array([[ 1, 1, 1, 1], [ 6, 6, 6, 6], [11, 11, 11, 11], [16, 16, 16, 16], [21, 21, 21, 21]], dtype=int32)

Сравнение

>>> np.broadcast_to(x[:,0,None], (5,4)) array([[ 1, 1, 1, 1], [ 6, 6, 6, 6], [11, 11, 11, 11], [16, 16, 16, 16], [21, 21, 21, 21]], dtype=int32)

13) Изменение формы массива с 1D на 2D

Ответ

strides = (24,8) shape = ( 4,3)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Смежные элементы на выходе (например, 1 → 2, 2 → 3, 7 → 8, 11 → 12) изначально находились на расстоянии 8 байтов друг от друга (= 1 элемент на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 3 .Выходное измерение сверху вниз (ось = -2):Смежные элементы в выходных данных (например, 1 → 4, 4 → 7, 7 → 10) изначально находились на расстоянии 24 байта друг от друга (= 3 элемента на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 4 .

Код

>>> x = np.asarray(range(1,13), np.int64) >>> as_strided(x, shape=(4,3), strides=(24,8)) array([[ 1, 2, 3], [ 4, 5, 6], [ 7, 8, 9], [10, 11, 12]])

Сравнение

>>> x.reshape(4,3) array([[ 1, 2, 3], [ 4, 5, 6], [ 7, 8, 9], [10, 11, 12]])

14) Сдвиг одномерного окна

Адаптировано из сообщения StackOverflow [ 1 ]. Аналогично [ 2 ] и [ 3 ].

Ответ

strides = (1,1) shape = (8,3)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 2, 3 → 4, 4 → 5) изначально находились на расстоянии 1 байта друг от друга (= 1 элемент на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 3 .Выходное измерение сверху вниз (ось = -2):Смежные элементы в выходных данных (т. е. 1 → 2, 2 → 3, 4 → 5, …, 7 → 8) изначально находились на расстоянии 1 байта друг от друга (= 1 элемент на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 8 .

Код

>>> x = np.asarray(range(1,26), np.int8) >>> as_strided(x, shape=(8,3), strides=(1,1)) array([[ 1, 2, 3], [ 2, 3, 4], [ 3, 4, 5], [ 4, 5, 6], [ 5, 6, 7], [ 6, 7, 8], [ 7, 8, 9], [ 8, 9, 10]], dtype=int8)

Сравнение

>>> # this may not be achieved concisely

15) Сдвиг 2D-окна, затем сглаживание

Вопрос взят из сообщения StackOverflow [ 4 ].

Ответ

strides = (2,1) shape = (4,6)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Смежные элементы в выходных данных (например, 0 → 1, 1 → 10, 31 → 40) изначально находились на расстоянии 1 байта друг от друга (= 1 элемент на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 6 .Выходное измерение сверху вниз (ось = -2):Соседние элементы на выходе (например, 0 → 10, 10 → 20, 41 → 51) изначально находились на расстоянии 2 байта друг от друга (= 2 элемента на расстоянии × 1 байт) на входе. Форма этого измерения равна 4 .

Код

>>> x = np.asarray( ... [0,1,10,11,20,21,30,31,40,41,50,51], ... np.int8).reshape(6,2) >>> as_strided(x, shape=(4,6), strides=(2,1)) array([[ 0, 1, 10, 11, 20, 21], [10, 11, 20, 21, 30, 31], [20, 21, 30, 31, 40, 41], [30, 31, 40, 41, 50, 51]], dtype=int8)

Сравнение

>>> # this may not be achieved concisely

16) Сворачивание оси из 3D-массива

Ответ

strides = (4,1) shape = (3,4)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 2, 3 → 4, 4 → 5) изначально находились на расстоянии 1 байта друг от друга (= 1 элемент на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 4 .Выходное измерение сверху вниз (ось = -2):Смежные элементы в выходных данных (т.е. 1 → 5, 5 → 9, 2 → 6, 6 → 10) изначально находились на расстоянии 4 байта друг от друга (= 4 элемента на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 3 .

Код

>>> x = np.asarray(range(1,13), np.int8).reshape(3,2,2) >>> as_strided(x, shape=(3,4), strides=(4,1)) array([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]], dtype=int8)

Сравнение

>>> x.reshape(3,4) array([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]], dtype=int8)

3D упражнения

17) 2 уголка

Ответ

strides = (30,10, 2) shape = ( 2, 2, 2)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Смежные элементы в выходных данных (т.е. 1 → 2, 6 → 7, 16 → 17, 21 → 22) изначально находились на расстоянии 2 байта друг от друга (= 1 элемент на расстоянии × 2 байта) во входных данных. Форма этого измерения равна 2 .Выходное измерение сверху вниз (ось = -2):Смежные элементы на выходе (т.е. 1 → 6, 2 → 7, 16 → 21, 17 → 22) изначально находились на расстоянии 10 байт друг от друга (= 5 элементов на расстоянии × 2 байта) на входе. Форма этого измерения равна 2 .Выходное измерение между коробками (ось = -3):Смежные элементы в выходных данных (т. е. 1 → 16, 2 → 17, 6 → 21, 7 → 22) изначально находились на расстоянии 30 байт друг от друга (= 15 элементов на расстоянии × 2 байта) во входных данных. Форма этого измерения равна 2 .

Код

>>> x = np.asarray(range(1,26), np.int16).reshape(5,5) >>> as_strided(x, shape=(2,2,2), strides=(30,10,2)) array([[[ 1, 2], [ 6, 7]], [[16, 17], [21, 22]]], dtype=int16)

Сравнение

>>> # this may not be achieved concisely

18) Нарезка в шахматном порядке

Ответ

strides = (10,6,1) shape = ( 2,2,3)

💡 ОбъяснениеИзмерение внутреннего поля вывода слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 2, 2 → 3, 17 → 18) изначально находились на расстоянии 1 байта друг от друга (= 1 элемент на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 3 .Измерение внутри блока вывода сверху вниз (ось = -2):Смежные элементы в выходных данных (например, 1 → 7, 11 → 17, 12 → 18) изначально находились на расстоянии 6 байтов друг от друга (= 6 элементов на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 2 .Размер выходного поля слева направо (ось = -3):Смежные элементы в выходных данных (например, 1 → 11, 8 → 18, 9 → 19) изначально находились на расстоянии 10 байт друг от друга (= 10 элементов на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 2 .

Код

>>> x = np.asarray(range(1,26), np.int8).reshape(5,5) >>> as_strided(x, shape=(2,2,3), strides=(10,6,1)) array([[[ 1, 2, 3], [ 7, 8, 9]], [[11, 12, 13], [17, 18, 19]]], dtype=int8)

Сравнение

>>> # this may not be achieved concisely

19) Повтор двумерного массива

Этот вопрос взят из сообщения StackOverflow здесь [ 5 ].

Ответ

strides = (0,10,2) shape = (3, 2,4)

💡 ОбъяснениеИзмерение внутреннего поля вывода слева направо (ось = -1):Соседние элементы на выходе (например, 1 → 2, 2 → 3, 6 → 7) изначально находились на расстоянии 2 байта друг от друга (= 1 элемент на расстоянии × 2 байта) на входе. Форма этого измерения равна 4 .Измерение внутри блока вывода сверху вниз (ось = -2):Соседние элементы на выходе (например, 1 → 6, 2 → 7, 3 → 8) изначально находились на расстоянии 10 байт друг от друга (= 5 элементов на расстоянии × 2 байта) на входе. Форма этого измерения равна 2 .Размер выходного поля слева направо (ось = -3):Смежные элементы в выходных данных (например, 1 → 1, 3 → 3, 7 → 7) изначально находились на расстоянии 0 байтов друг от друга (= 0 элементов на расстоянии × 2 байта) во входных данных. Форма этого измерения равна 3 .

Код

>>> x = np.asarray(range(1,26), np.int16).reshape(5,5) >>> as_strided(x, shape=(3,2,4), strides=(0,10,2)) array([[[1, 2, 3, 4], [6, 7, 8, 9]], [[1, 2, 3, 4], [6, 7, 8, 9]], [[1, 2, 3, 4], [6, 7, 8, 9]]], dtype=int16)

Сравнение

>>> np.broadcast_to(x[0:2, 0:-1], (3, 2, 4))

20) 3D транспонирование

Ответ

strides = (16,4,8) shape = ( 3,2,2)

💡 ОбъяснениеВыходное измерение слева направо (ось = -1):Соседние элементы на выходе (например, 1 → 3, 2 → 4, 10 → 12) изначально находились на расстоянии 8 байтов друг от друга (= 2 элемента на расстоянии × 4 байта) на входе. Форма этого измерения равна 2 .Выходное измерение сверху вниз (ось = -2):Смежные элементы на выходе (например, 1 → 2, 3 → 4, 9 → 10, 11 → 12) изначально находились на расстоянии 4 байта друг от друга (= 1 элемент на расстоянии × 4 байта) на входе. Форма этого измерения равна 2 .Размер выходного поля слева направо (ось = -3):Соседние элементы на выходе (например, 1 → 5, 5 → 9) изначально находились на расстоянии 16 байтов друг от друга (= 4 элемента на расстоянии × 4 байта) на входе. Форма этого измерения равна 3 .

Код

>>> x = np.asarray(range(1,13), np.int32).reshape(3,2,2) >>> as_strided(x, shape=(3,2,2), strides=(16,4,8)) array([[[ 1, 3], [ 2, 4]], [[ 5, 7], [ 6, 8]], [[ 9, 11], [10, 12]]], dtype=int32)

Сравнение

>>> np.swapaxes(x,1,2) array([[[ 1, 3], [ 2, 4]], [[ 5, 7], [ 6, 8]], [[ 9, 11], [10, 12]]], dtype=int32)

21) Сдвиг 2D-окна

Вопрос адаптирован из конференции SciPy 2008 [ 6 ].

Ответ

strides = (40,40,8) shape = ( 3, 2,5)

💡 ОбъяснениеИзмерение внутреннего поля вывода слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 2, 12 → 13, 16 → 17) изначально находились на расстоянии 8 байтов друг от друга (= 1 элемент на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 5 .Измерение внутри блока вывода сверху вниз (ось = -2):Смежные элементы в выходных данных (например, 1 → 6, 8 → 13, 11 → 16) изначально находились на расстоянии 40 байт друг от друга (= 5 элементов на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 2 .Размер выходного поля слева направо (ось = -3):Смежные элементы в выходных данных (например, 9 → 14, 14 → 19) изначально находились на расстоянии 40 байт друг от друга (= 5 элементов на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 3 .

Код

>>> x = np.asarray(range(1,21), np.int64).reshape(4,5) >>> as_strided(x, shape=(3,2,5), strides=(40,40,8)) array([[[ 1, 2, 3, 4, 5], [ 6, 7, 8, 9, 10]], [[ 6, 7, 8, 9, 10], [11, 12, 13, 14, 15]], [[11, 12, 13, 14, 15], [16, 17, 18, 19, 20]]])

Сравнение

>>> # this may not be achieved concisely

22) Изменение формы массива с 1D на 3D

Ответ

strides = (6,3,1) shape = (2,2,3)

💡 ОбъяснениеИзмерение внутреннего поля вывода слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 2, 5 → 6, 7 → 8, 10 → 11) изначально находились на расстоянии 1 байта друг от друга (= 1 элемент на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 3 .Измерение внутри блока вывода сверху вниз (ось = -2):Соседние элементы на выходе (например, 1 → 4, 2 → 5, 8 → 11) изначально находились на расстоянии 3 байта друг от друга (= 3 элемента на расстоянии × 1 байт) на входе. Форма этого измерения равна 2 .Размер выходного поля слева направо (ось = -3):Смежные элементы в выходных данных (например, 1 → 7, 2 → 8, 3 → 9) изначально находились на расстоянии 6 байтов друг от друга (= 6 элементов на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 2 .

Код

>>> x = np.asarray(range(1,13), np.int8) >>> as_strided(x, shape=(2,2,3), strides=(6,3,1)) array([[[ 1, 2, 3], [ 4, 5, 6]], [[ 7, 8, 9], [10, 11, 12]]], dtype=int8)

Сравнение

>>> x.reshape(2,2,3) array([[[ 1, 2, 3], [ 4, 5, 6]], [[ 7, 8, 9], [10, 11, 12]]], dtype=int8)

4D упражнения

23) Сдвиг 2D рецептивного поля

Адаптировано из публикации StackOverflow о 2D-свертке здесь [ 7 ].

Ответ

strides = (10,2,5,1) shape = ( 2,2,3,3)

💡 ОбъяснениеИзмерение внутреннего поля вывода слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 2, 17 → 18, 24 → 25) изначально находились на расстоянии 1 байта друг от друга (= 1 элемент на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 3 .Измерение внутри блока вывода сверху вниз (ось = -2):Смежные элементы в выходных данных (например, 1 → 6, 2 → 7, 3 → 8) изначально находились на расстоянии 5 байтов друг от друга (= 5 элементов на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 3 .Размер выходного поля слева направо (ось = -3):Смежные элементы в выводе (например, 1 → 3, 6 → 8, 21 → 23, 23 → 25) изначально находились на расстоянии 2 байта друг от друга (= 2 элемента на расстоянии × 1 байт) во входных данных. Форма этого измерения равна 2 .Расстояние между верхним и нижним прямоугольниками вывода (ось = -4):Смежные элементы на выходе (например, 1 → 11, 2 → 12, 15 → 25) изначально находились на расстоянии 10 байт друг от друга (= 10 элементов на расстоянии × 1 байт) на входе. Форма этого измерения равна 2 .

Код

>>> x = np.asarray(range(1,26), np.int8).reshape(5,5) >>> as_strided(x, shape=(2,2,3,3), strides=(10,2,5,1)) array([[[[ 1, 2, 3], [ 6, 7, 8], [11, 12, 13]], [[ 3, 4, 5], [ 8, 9, 10], [13, 14, 15]]], [[[11, 12, 13], [16, 17, 18], [21, 22, 23]], [[13, 14, 15], [18, 19, 20], [23, 24, 25]]]], dtype=int8)

Сравнение

>>> # this may not be achieved concisely

24) Повтор трёхмерного тензора

Ответ

strides = (48, 0,24, 8) shape = ( 2, 2, 2, 3)

💡 ОбъяснениеИзмерение внутреннего поля вывода слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 2, 2 → 3, 4 → 5) изначально находились на расстоянии 8 байтов друг от друга (= 1 элемент на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 3 .Измерение внутри блока вывода сверху вниз (ось = -2):Соседние элементы на выходе (например, 1 → 4, 7 → 10, 8 → 11) изначально находились на расстоянии 24 байта друг от друга (= 3 элемента на расстоянии × 8 байтов) на входе. Форма этого измерения равна 2 .Размер выходного поля слева направо (ось = -3):Смежные элементы в выходных данных (например, 1 → 1, 10 → 10, 12 → 12) изначально находились на расстоянии 0 байтов друг от друга (= 0 элементов на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 2 .Расстояние между верхним и нижним прямоугольниками вывода (ось = -4):Смежные элементы в выходных данных (например, 1 → 7, 2 → 8, 3 → 9) изначально находились на расстоянии 48 байт друг от друга (= 6 элементов на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 2 .

Код

>>> x = np.asarray(range(1,13), np.int64).reshape(2,2,3) >>> as_strided(x, shape=(2,2,2,3), strides=(48,0,24,8)) array([[[[ 1, 2, 3], [ 4, 5, 6]], [[ 1, 2, 3], [ 4, 5, 6]]], [[[ 7, 8, 9], [10, 11, 12]], [[ 7, 8, 9], [10, 11, 12]]]])

Сравнение

>>> np.broadcast_to(x,(2,2,2,3)).swapaxes(0,1) array([[[[ 1, 2, 3], [ 4, 5, 6]], [[ 1, 2, 3], [ 4, 5, 6]]], [[[ 7, 8, 9], [10, 11, 12]], [[ 7, 8, 9], [10, 11, 12]]]])

25) Изменение формы массива с 1D на 4D

Ответ

strides = (64,32,16, 8) shape = ( 2, 2, 2, 2)

💡 ОбъяснениеИзмерение внутреннего поля вывода слева направо (ось = -1):Смежные элементы в выходных данных (например, 1 → 2, 2 → 3, 4 → 5) изначально находились на расстоянии 8 байтов друг от друга (= 1 элемент на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 2 .Измерение внутри блока вывода сверху вниз (ось = -2):Смежные элементы в выходных данных (например, 1 → 4, 7 → 10, 8 → 11) изначально находились на расстоянии 16 байтов друг от друга (= 2 элемента на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 2 .Размер выходного поля слева направо (ось = -3):Смежные элементы на выходе (например, 1 → 1, 10 → 10, 12 → 12) изначально находились на расстоянии 32 байта друг от друга (= 4 элемента на расстоянии × 8 байтов) на входе. Форма этого измерения равна 2 .Расстояние между верхним и нижним прямоугольниками вывода (ось = -4):Смежные элементы в выходных данных (например, 1 → 7, 2 → 8, 3 → 9) изначально находились на расстоянии 64 байта друг от друга (= 8 элементов на расстоянии × 8 байтов) во входных данных. Форма этого измерения равна 2 .

Код

>>> x = np.asarray(range(1,17), np.int64) >>> as_strided(x, shape=(2,2,2,2), strides=(64,32,16,8)) array([[[[ 1, 2], [ 3, 4]], [[ 5, 6], [ 7, 8]]], [[[ 9, 10], [11, 12]], [[13, 14], [15, 16]]]])

Сравнение

>>> x.reshape(2,2,2,2) array([[[[ 1, 2], [ 3, 4]], [[ 5, 6], [ 7, 8]]], [[[ 9, 10], [11, 12]], [[13, 14], [15, 16]]]])

⚠ В то время как трюки с шагами дают вам больше контроля над результирующим представлением NumPy, API не является безопасным для памяти — всё может стать довольно неприятным, если вы неправильно рассчитаете размер элемента (честно говоря, я думаю, что этот API не должен позволять клиентскому коду иметь дело с размером элемента, поскольку я не видел никаких преимуществ в раскрытии этого) или формы или существующих шагов, возвращая данные, которые на самом деле не являются исходным массивом, который вы создали, а из другого массива, который вы, вероятно, определили несколькими строками назад 😱. Это понятие известно как переполнение буфера , и с этим нетрудно столкнуться.

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

Ресурсы

Расширенный NumPy (scipy-lectures.org)

0
Комментарии
-3 комментариев
Раскрывать всегда