В этой статье мы рассмотрим ряд различных упражнений, используя библиотеку NumPy (и сравним с тем, как мы бы реализовали их без неё). В самом конце статьи я приведу ряд упражнений.
t.me/ai_machinelearning_big_data — моем телеграм канале я публикую актуальные проекты курсы, уроки и примеры с кодом по машинному обучению.
Для этой статьи рекомендуется, чтобы читатель имел средний уровень знаний Python, NumPy, numpy.dtype, numpy.ndarray.strides, и numpy.ndarray.itemsize. Краткое введение в массивы и NumPy см. в разделе ? Немного предыстории ниже.
Рекомендуемые бесплатные курсы и гайды:
-
Я собрал папку полезных обучающих каналов по Машинному обучению и Анализу данных
-
Подборка бесплатных курсов для получения степени в области Data Science
-
Бесплатный курс язык программирования Python в задачах машинного обучения
Упражнения расположены по возрастающей сложности. Вот структура каждого из упражнений:
-
Вопрос, показанный в виде диаграммы с вводом массива 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 трюков с шагами может быть сложным, и даже у меня были проблемы с этим. Однако трюк (без каламбура) заключается в том, чтобы начать с меньших размеров и визуализировать вывод тензоров. Веселитесь!
Что выведет код?
Задача 1
import numpy as np x = np.array([1, 4, 9, 16]) print(np.mean(x))
Задача 2
import numpy as np data = np.array([2, 7, 3, 1]) bins = [0, 5, 10] hist, _ = np.histogram(data, bins) print(*hist) #data - набор данных #bins - набор интервалов, задаваемых граничными значениями
Задача 3
Что выведет код? import numpy as np x = np.array([1., 2., np.nan]) print(np.nanstd(x))
Задача 4
import numpy as np x = np.fmin([1, -5, 6], [0, np.nan, -1]) print(*x)
Задача 5
mport numpy as np # Данные: каждая строка соответствует корзине для покупок конкретного покупателя # строка = [товар 1, товар 2, товар 3] # значение 1 означает, что товар был куплен basket = np.array([[1, 1, 0], [0, 0, 1], [1, 0, 0], [1, 1, 1], [1, 1, 0]]) copurchases = [(i, j, np.sum(basket[:, i] + basket[:, j] == 2)) for i in range(3) for j in range(i+1, 3)] result = max(copurchases, key=lambda x:x[2]) # Первые два значения кортежа result - индексы товаров-столбцов. Третье - число раз, когда они покупались вместе. print(result)
Задача 6
Задача регрессии. Площади квартир соответствует некая их стоимость. Вычислите предположительную стоимость квартиры площадью 30 кв м. from sklearn.neighbors import KNeighborsRegressor import numpy as np X = np.array([[35, 30000], [45, 45000], [40, 50000], [35, 35000], [25, 32500], [40, 40000]]) KNN = KNeighborsRegressor(n_neighbors=3).fit(X[:,0].reshape(-1,1), X[:,1]) res = KNN.predict([[30]]) print(int(res[0]))
Задача 7
Массив данных basket содержит по одной строке для каждого покупателя и по столбцу для каждого товара. Значение 1 в ячейке (i,j) означает, что покупатель i купил товар j. Дан код: import numpy as np basket = np.array([[1, 1, 1, 1], [1, 1, 1, 0]]) co_purchases = np.sum(np.all(basket[:,2:], axis = 1)) / basket.shape[0] print(co_purchases)
Задача 8
Что выведет код? import numpy as np x = np.fmin([1, -5, 6], [0, np.nan, -1]) print(*x)
Задача 9
import numpy as np a = np.array([1, 2, np.nan, np.nan]) print(np.max(a), np.nanmax(a))
Задача 10
import numpy as np basket = np.array([[1, 1, 1, 1], [1, 1, 1, 0]]) x = np.all(basket[:,2:], axis = 1) print(*x)
На этом все, спасибо , за прочтение, пишите свои ответы в комментариях
Ресурсы
Numpy полный бесплатный курс (YouTube)
N-мерный массив (ndarray) (numpy.org)
5 лучших функций создания массивов в Numpy для начинающих
https://uproger.com/prodvinutyj-numpy-ottachivajte-tryuki-s-shagami/
Расширенный NumPy (scipy-lectures.org)
Иллюстрированное руководство по форме и шагам (ajcr.net)
Использование трюков с шагом с NumPy (ipython-books.github.io)
[2] https://stackoverflow.com/questions/4923617/efficient-numpy-2d-array-construction-from-1d-array
[4] https://stackoverflow.com/questions/15722324/sliding-window-of-m-by-n-shape-numpy-ndarray
[5] https://stackoverflow.com/questions/23695851/python-repeating-numpy-array-without-replicating-data
[6] https://mentat.za.net/numpy/numpy_advanced_slides/
[7] https://stackoverflow.com/questions/43086557/convolve2d-just-by-using-numpy
ссылка на оригинал статьи https://habr.com/ru/articles/784978/
Добавить комментарий