python任意累积_python numpy einsum用法及代码示例

在操作数上评估爱因斯坦求和约定。

使用爱因斯坦求和约定,可以以简单的方式表示许多常见的多维线性代数数组运算。在隐式模式下einsum计算这些值。

在显式模式下,einsum通过禁用或强制对指定的下标标签求和,可以提供更大的灵活性来计算其他数组操作,而这些操作可能不被视为经典的爱因斯坦求和操作。

请参阅注释和示例以进行澄清。

参数:subscripts: : str

将要求和的下标指定为下标标签的逗号分隔列表。除非包含显式指示符“->”以及精确输出形式的下标标签,否则将执行隐式(经典的爱因斯坦求和)计算。

operands: : list of array_like

这些是用于操作的数组。

out: : ndarray, 可选参数

如果提供的话,将在此数组中进行计算。

dtype: : {data-type, None}, 可选参数

如果提供,则强制计算使用指定的数据类型。请注意,您可能还必须提供一个更宽松的转换参数以允许进行转换。默认为无。

order: : {‘C’, ‘F’, ‘A’, ‘K’}, 可选参数

控制输出的内存布局。 ‘C’表示它应该是C连续的。 ‘F’表示它应该是Fortran连续的,‘A’表示如果所有输入都为‘F’,则它应该是‘F’,否则为‘C’。 ‘K’表示它应尽可能靠近输入,包括任意排列的轴,尽可能靠近布局。默认值为‘K’。

casting: : {‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, 可选参数

控制可能发生的数据类型转换。不建议将其设置为‘unsafe’,因为它可能会对累积产生不利影响。

‘no’ means the data types should not be cast at all.

‘equiv’ means only byte-order changes are allowed.

‘safe’ means only casts which can preserve values are allowed.

‘same_kind’ means only safe casts or casts within a kind,

like float64 to float32, are allowed.

‘unsafe’ means any data conversions may be done.

默认值为‘safe’。

optimize: : {False, True, ‘greedy’, ‘optimal’}, 可选参数

控制是否应该进行中间优化。如果False和True将默认设置为‘greedy’算法,则不会进行优化。还接受来自np.einsum_path功能。看到np.einsum_path更多细节。默认为False。

返回值:output: : ndarray

基于爱因斯坦求和约定的计算。

注意:

1.6.0版中的新功能。

爱因斯坦求和约定可用于计算许多多维的线性代数数组运算。einsum提供了一种简洁的表示方式。

这些操作的非详尽列表,可以通过以下方式计算einsum,以及示例如下所示:

下标字符串是用逗号分隔的下标标签列表,其中每个标签均指相应操作数的维。每当重复标签时,都会对其求和,因此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, axis=-1)和np.einsum('ii->i', a)就好像np.diag(a)。区别在于einsum默认情况下不允许广播。另外np.einsum('ij,jh->ih', a, b)直接指定输出下标标签的顺序,因此返回矩阵乘法,这与上面的隐式模式示例不同。

要启用和控制广播,请使用省略号。默认的NumPy-style广播是通过在每个术语的左侧添加省略号来完成的,例如np.einsum('...ii->...i', a)。要沿第一个轴和最后一个轴进行跟踪,您可以np.einsum('i...i', a),或者使用left-most索引而不是最右端的索引来制作matrix-matrix产品,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)将返回2D数组对角线的可写视图。

1.12.0版中的新功能。

添加了optimize参数将优化einsum表达式的收缩顺序。对于具有三个或更多操作数的压缩,这可以大大提高计算效率,但需要在计算过程中增加内存占用量。

通常应用‘greedy’算法,根据经验测试,该算法在大多数情况下会返回最佳路径。在某些情况下,‘optimal’将通过更昂贵,更详尽的搜索返回最高级路径。对于迭代计算,建议一次计算最佳路径,然后通过将其作为参数提供来重用该路径。下面给出一个例子。

例子:

>>> 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]])

链式数组操作。对于更复杂的收缩,可以通过重复计算‘greedy’路径或预先计算‘optimal’路径并重复使用来应用,以加快速度。einsum_path插入(自1.12.0版开始)。对于较大的阵列,性能改进尤其重要:

>>> a = np.ones(64).reshape(2,4,8)

基本的einsum:〜1520ms(以3.1GHz Intel i5为基准)

>>> for iteration in range(500):

... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a)

Sub-optimaleinsum(由于重复的路径计算时间):〜330ms

>>> for iteration in range(500):

... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a, optimize='optimal')

贪婪einsum(更快的最佳路径逼近):〜160ms

>>> for iteration in range(500):

... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a, optimize='greedy')

最佳einsum(在某些情况下为最佳使用模式):〜110ms

>>> 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)

你可能感兴趣的:(python任意累积)