numpy.einsum
- numpy.einsum(subscripts, *operands, out=None, dtype=None, order='K', casting='safe', optimize=False)[source]
-
Вычисляет соглашение об индексно-суммарном сокращении для операндов.
Используя соглашение об индексно-суммарном сокращении, многие распространённые многомерные операции линейной алгебры над массивами можно представить простым способом. В неявном режиме
einsumвычисляет эти значения.В явном режиме,
einsumпредоставляет дополнительную гибкость для вычисления других операций с массивами, которые могут не считаться классическими операциями индексно-суммарного сокращения, отключив или принудительно выполняя суммирование по заданным индексным меткам.См. примечания и примеры для разъяснения.
- Параметры:
-
- subscriptsstr
-
Указывает индексы для суммирования как список индексных меток, разделённых запятыми. Выполняется неявное (классическое индексно-суммарное сокращение) вычисление, если не указан явный индикатор ‘->’, а также индексные метки точного выходного формата.
- operandslist of array_like
-
Это массивы для операции.
- outndarray, optional
-
Если предоставлено, вычисление выполняется в этом массиве.
- dtype{data-type, None}, optional
-
Если предоставлено, принудительно использует указанный тип данных. Обратите внимание, что вам может потребоваться также указать более общий
castingпараметр, чтобы разрешить преобразования. По умолчанию равно None. - order{‘C’, ‘F’, ‘A’, ‘K’}, optional
-
Управляет расположением памяти выходных данных. ‘C’ означает, что оно должно быть C-непрерывным. ‘F’ означает, что оно должно быть Fortran-непрерывным, ‘A’ означает, что оно должно быть ‘F’, если все входные данные — ‘F’, в противном случае — ‘C’. ‘K’ означает, что оно должно быть максимально близким к расположению входных данных, включая произвольно перестановки осей. По умолчанию равно ‘K’.
- casting{‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optional
-
Управляет видом преобразования данных, которое может произойти. Установка этого значения в ‘unsafe’ не рекомендуется, поскольку это может отрицательно сказаться на накоплении.
- ‘no’ означает, что типы данных вообще не должны быть преобразованы.
- ‘equiv’ означает, что разрешены только изменения порядка байтов.
- ‘safe’ означает, что разрешены только преобразования, которые могут сохранить значения.
- ‘same_kind’ означает, что разрешены только безопасные преобразования или преобразования в рамках одного типа, например, float64 в float32.
- ‘unsafe’ означает, что могут быть выполнены любые преобразования данных.
По умолчанию равно ‘safe’.
- optimize{False, True, ‘greedy’, ‘optimal’}, optional
-
Управляет тем, должно ли происходить промежуточное оптимизация. Если False, оптимизация не будет происходить, а True по умолчанию использует алгоритм ‘greedy’. Также принимает явный список сокращений из функции
np.einsum_path. См.np.einsum_pathдля получения дополнительной информации. По умолчанию равно False.
- Возвращаемое значение:
-
- outputndarray
-
Вычисление, основанное на соглашении об индексно-суммарном сокращении.
См. также
-
einsum_path,dot,inner,outer,tensordot,linalg.multi_dot einsum-
Аналогичный подробный интерфейс предоставляет пакет einops для покрытия дополнительных операций: транспонирование, изменение формы/сглаживание, повторение/дублирование, сжатие/расширение и сокращения. opt_einsum оптимизирует порядок сокращения для выражений типа einsum независимо от бэкенда.
Примечания
Введено в версии 1.6.0.
Соглашение об индексно-суммарном сокращении можно использовать для вычисления многих многомерных операций линейной алгебры над массивами.
einsumпредоставляет компактный способ их представления.Ниже приведён неполный список таких операций, которые можно вычислить с помощью
einsum, вместе с примерами:- След массива,
numpy.trace. - Возврат диагонали,
numpy.diag. - Суммирование по осям массива,
numpy.sum. - Транспонирование и перестановки,
numpy.transpose. -
- Умножение матриц и скалярное произведение,
numpy.matmul
- Умножение матриц и скалярное произведение,
-
- Внутренние и внешние произведения векторов,
numpy.inner
- Внутренние и внешние произведения векторов,
-
- Расширение, поэлементное и скалярное умножение,
- Сжатия тензоров,
numpy.tensordot. -
- Цепочки операций с массивами в эффективном порядке вычисления,
Строка индексов — это список индексных меток, разделённых запятыми, где каждая метка относится к размерности соответствующего операнда. Когда метка повторяется, она суммируется, поэтому
np.einsum('i,i', a, b)эквивалентноnp.inner(a,b). Если метка встречается только один раз, она не суммируется, поэтомуnp.einsum('i', a)создаёт представлениеaбез изменений. Ещё один примерnp.einsum('ij,jk', a, b)описывает традиционное умножение матриц и эквивалентноnp.matmul(a,b). Повторяющиеся индексные метки в одном операнде принимают диагональные значения. Например,np.einsum('ii', a)эквивалентноnp.trace(a).В неявном режиме выбранные индексы важны, так как оси выходных данных переупорядочиваются по алфавиту. Это означает, что
np.einsum('ij', a)не влияет на 2D-массив, тогда какnp.einsum('ji', a)переворачивает его. Кроме того,np.einsum('ij,jk', a, b)возвращает произведение матриц, аnp.einsum('ij,jh', a, b)возвращает транспонированное произведение, так как индексная метка ‘h’ предшествует индексной метке ‘i’.В явном режиме выходные данные можно напрямую контролировать, указав индексные метки выходных данных. Это требует идентификатора ‘->’, а также списка индексных меток выходных данных. Эта функция повышает гибкость функции, так как суммирование можно отключить или принудительно выполнить при необходимости. Вызов
np.einsum('i->', a)аналогиченnp.sum(a), еслиa— это одномерный массив, иnp.einsum('ii->i', a)аналогиченnp.diag(a), еслиa— это квадратный 2D-массив. Разница в том, чтоeinsumпо умолчанию не поддерживает расширение. Кроме того,np.einsum('ij,jh->ih', a, b)непосредственно указывает порядок индексных меток выходных данных и поэтому возвращает произведение матриц, в отличие от примера выше в неявном режиме.Для включения и управления расширением используйте эллипсис. Расширение по умолчанию в стиле NumPy выполняется путём добавления эллипса слева от каждого члена, как
np.einsum('...ii->...i', a).np.einsum('...i->...', a)аналогичноnp.sum(a, axis=-1)для массиваaлюбой формы. Для вычисления следа по первой и последней осям можно использоватьnp.einsum('i...i', a), а для выполнения умножения матриц-матриц с левыми индексами вместо правых —np.einsum('ij...,jk...->ik...', a, b).Если существует только один операнд, оси не суммируются, и параметр вывода не предоставляется, вместо нового массива возвращается представление операнда. Таким образом, взятие диагонали как
np.einsum('ii->i', a)создаёт представление (изменено в версии 1.10.0).einsumтакже предоставляет альтернативный способ предоставления индексов и операндов в видеeinsum(op0, sublist0, op1, sublist1, ..., [sublistout]). Если форма вывода не задана в этом формате,einsumбудет вычисляться в неявном режиме, в противном случае — в явном.Примеры ниже имеют соответствующие вызовы
einsumс методами с двумя параметрами.Введено в версии 1.10.0.
Возвращаемые из einsum представления теперь могут быть изменяемыми, когда входной массив изменяем. Например,
np.einsum('ijk...->kji...', a)теперь будет иметь тот же эффект, что иnp.swapaxes(a, 0, 2), аnp.einsum('ii->i', a)вернёт изменяемое представление диагонали двумерного массива.Новая функция в версии 1.12.0.
Добавлен аргумент
optimize, который оптимизирует порядок сокращения в выражении einsum. Для сокращения с тремя или более операндами это может значительно повысить вычислительную эффективность за счёт увеличения потребления памяти во время вычислений.Обычно применяется алгоритм «жадный» (greedy), который в большинстве случаев, по результатам эмпирических тестов, возвращает оптимальный путь. В некоторых случаях «оптимальный» (optimal) вернёт наилучший путь с помощью более дорогостоящего и полного поиска. Для итеративных вычислений может быть целесообразно вычислить оптимальный путь один раз и повторно использовать этот путь, передав его в качестве аргумента. Пример приведён ниже.
См.
numpy.einsum_pathдля получения более подробной информации.Примеры
>>> a = np.arange(25).reshape(5,5) >>> b = np.arange(5) >>> c = np.arange(6).reshape(2,3)
След матрицы:
>>> np.einsum('ii', a) 60 >>> np.einsum(a, [0,0]) 60 >>> np.trace(a) 60Извлечение диагонали (требуется явный вид):
>>> np.einsum('ii->i', a) array([ 0, 6, 12, 18, 24]) >>> np.einsum(a, [0,0], [0]) array([ 0, 6, 12, 18, 24]) >>> np.diag(a) array([ 0, 6, 12, 18, 24])Суммирование по оси (требуется явный вид):
>>> np.einsum('ij->i', a) array([ 10, 35, 60, 85, 110]) >>> np.einsum(a, [0,1], [0]) array([ 10, 35, 60, 85, 110]) >>> np.sum(a, axis=1) array([ 10, 35, 60, 85, 110])Для многомерных массивов суммирование по одной оси может быть выполнено с помощью эллипса:
>>> np.einsum('...j->...', a) array([ 10, 35, 60, 85, 110]) >>> np.einsum(a, [Ellipsis,1], [Ellipsis]) array([ 10, 35, 60, 85, 110])Вычисление транспонирования матрицы или переупорядочивание любого количества осей:
>>> np.einsum('ji', c) array([[0, 3], [1, 4], [2, 5]]) >>> np.einsum('ij->ji', c) array([[0, 3], [1, 4], [2, 5]]) >>> np.einsum(c, [1,0]) array([[0, 3], [1, 4], [2, 5]]) >>> np.transpose(c) array([[0, 3], [1, 4], [2, 5]])Внутренние произведения векторов:
>>> np.einsum('i,i', b, b) 30 >>> np.einsum(b, [0], b, [0]) 30 >>> np.inner(b,b) 30Умножение матрицы на вектор:
>>> np.einsum('ij,j', a, b) array([ 30, 80, 130, 180, 230]) >>> np.einsum(a, [0,1], b, [1]) array([ 30, 80, 130, 180, 230]) >>> np.dot(a, b) array([ 30, 80, 130, 180, 230]) >>> np.einsum('...j,j', a, b) array([ 30, 80, 130, 180, 230])Расширение и умножение на скаляр:
>>> np.einsum('..., ...', 3, c) array([[ 0, 3, 6], [ 9, 12, 15]]) >>> np.einsum(',ij', 3, c) array([[ 0, 3, 6], [ 9, 12, 15]]) >>> np.einsum(3, [Ellipsis], c, [Ellipsis]) array([[ 0, 3, 6], [ 9, 12, 15]]) >>> np.multiply(3, c) array([[ 0, 3, 6], [ 9, 12, 15]])Внешнее произведение векторов:
>>> np.einsum('i,j', np.arange(2)+1, b) array([[0, 1, 2, 3, 4], [0, 2, 4, 6, 8]]) >>> np.einsum(np.arange(2)+1, [0], b, [1]) array([[0, 1, 2, 3, 4], [0, 2, 4, 6, 8]]) >>> np.outer(np.arange(2)+1, b) array([[0, 1, 2, 3, 4], [0, 2, 4, 6, 8]])Сжатие тензора:
>>> a = np.arange(60.).reshape(3,4,5) >>> b = np.arange(24.).reshape(4,3,2) >>> np.einsum('ijk,jil->kl', a, b) array([[4400., 4730.], [4532., 4874.], [4664., 5018.], [4796., 5162.], [4928., 5306.]]) >>> np.einsum(a, [0,1,2], b, [1,0,3], [2,3]) array([[4400., 4730.], [4532., 4874.], [4664., 5018.], [4796., 5162.], [4928., 5306.]]) >>> np.tensordot(a,b, axes=([1,0],[0,1])) array([[4400., 4730.], [4532., 4874.], [4664., 5018.], [4796., 5162.], [4928., 5306.]])Изменяемые возвращаемые массивы (с версии 1.10.0):
>>> a = np.zeros((3, 3)) >>> np.einsum('ii->i', a)[:] = 1 >>> a array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]])Пример использования эллипса:
>>> a = np.arange(6).reshape((3,2)) >>> b = np.arange(12).reshape((4,3)) >>> np.einsum('ki,jk->ij', a, b) array([[10, 28, 46, 64], [13, 40, 67, 94]]) >>> np.einsum('ki,...k->i...', a, b) array([[10, 28, 46, 64], [13, 40, 67, 94]]) >>> np.einsum('k...,jk', a, b) array([[10, 28, 46, 64], [13, 40, 67, 94]])Цепочечные операции с массивами. Для более сложных сокращений ускорение может быть достигнуто путём повторного вычисления «жадного» пути или предварительного вычисления «оптимального» пути и его многократного применения, используя вставку
einsum_path(с версии 1.12.0). Улучшение производительности может быть особенно значительным при работе с большими массивами:>>> a = np.ones(64).reshape(2,4,8)
Базовая функция
einsum: ~1520 мс (измерение на процессоре Intel i5 3.1 ГГц.)>>> for iteration in range(500): ... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a)Неоптимальная функция
einsum(из-за времени повторного вычисления пути): ~330 мс>>> for iteration in range(500): ... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a, ... optimize='optimal')Жадный (greedy) вариант
einsum(быстрое приближение оптимального пути): ~160 мс>>> for iteration in range(500): ... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a, optimize='greedy')Оптимальный вариант
einsum(лучшая модель использования в некоторых случаях): ~110 мс>>> path = np.einsum_path('ijk,ilm,njm,nlk,abc->',a,a,a,a,a, ... optimize='optimal')[0] >>> for iteration in range(500): ... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a, optimize=path)
© 2005–2024 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/2.0/reference/generated/numpy.einsum.html