【NumPy】爱因斯坦求和约定

标记法

NumPy方法名称einsum,其全称是Einstein summation convention(爱因斯坦求和约定),又称为爱因斯坦标记法(Einstein notation)。在处理关于坐标的方程式时,这个方法非常有用。这是由大名鼎鼎的物理学家阿尔伯特·爱因斯坦(Albert Einstein)于1916年提出的。
这种约定,简单来说,就是省去了求和式中的求和符号。我们来看下面的点乘公式。
s = ∑ i v i w i s=\sum_iv_iw_i s=iviwi
这个公式表述的是,两个向量对应的元素相乘后求和。这种写法于我们而言,已然熟稔于心。可爱因斯坦偏偏觉得这种数学符号太过于烦琐,他觉得那个求和符号纯属多余,于是他发明了另外一种写法。
s = v i w i s=v_iw^i s=viwi
请特别注意,在爱因斯坦的标记体系里,下标表示行向量中的元素:
KaTeX parse error: Undefined control sequence: \cdts at position 10: [v_1,v_2,\̲c̲d̲t̲s̲,v_k]
但上标并不表示指数,而表示列向量中的元素:
[ w 1 w 2 ⋯ w k ] \begin{bmatrix} w^1\\w^2\\\cdots\\w^k\end{bmatrix} w1w2wk

  1. 内积:
    u ⋅ v = u j v i u·v=u_jv^i uv=ujvi
  2. 向量乘以矩阵:矩阵 A A A和向量 v v v的乘积向量 u u u
    u i = A j i v j u^i=A^i_jv^j ui=Ajivj
  3. 矩阵乘法:矩阵 A i ∗ j A_{i*j} Aij和矩阵 B j ∗ k B_{j*k} Bjk,二者乘法
    C k i = A j i B k j C^i_k=A^i_jB^j_k Cki=AjiBkj
  4. 矩阵的迹:对于一个矩阵A,如果矩阵的上标与下标相同,则可以得到这个矩阵的迹t。
    t = A i i t=A^i_i t=Aii
  5. 外积:M维向量a和N维余向量b的外积是一个M×N的矩阵A。
    A = a b A=ab A=ab

如果采用爱因斯坦标记法,上述公式可以表示如下。
A j i = a i b j A^i_j=a^ib_j Aji=aibj
由于i和j代表两个不同的标号,外积不会除去这两个标号,于是这两个标号变成了新矩阵A的标号。

NumPy中的einsum()方法

格式:

result = np.einsum("{}, {}, {}->{}", arg0, arg1, arg2)

einsum()方法,在理论上,可以支持任意多的参数。该方法的第一个参数—格式字符串,至关重要,它直接决定整个方法实现的功能。格式字符串的规定如下。

  • 不同的输入变量格式字符之间要用逗号分隔开,且输入格式字符的数量要与参与运算的变量数量相匹配。
  • 输入格式字符和输出格式字符要用箭头分隔开。
  • 输入格式字符和输出格式字符都是一系列常见字符(如ASCII码)。
  • 格式字符串中的字符数(字符串长度)和张量的维数相对应。

np.einsum()的用法

import numpy as np

arr = np.arange(10)
print("\narr: \n{}".format(arr))
sum1 = np.einsum('i->', arr)
print("\nsum1: {}".format(sum1))
======================================
arr: 
[0 1 2 3 4 5 6 7 8 9]

sum1: 45

格式字符串'i->'表示的是一个一维张量(箭头前面的字符长度为1),它的维度消失了(箭头后面的字符为空,其实是变成了一个标量),怎么才能达到这个效果呢?再结合einsum()方法的关键词“sum”可知,原来是通过“求和”达成的“约减”。

按行求和 按列求和

如果按照上述逻辑,巧妙利用einsum()中的格式字符,我们可以很容易实现“按行求和”或“按列求和”的操作。

arr2 = np.arange(20).reshape(4, 5)
print("\narr2:\n{}".format(arr2))
sum_col = np.einsum('ij->j', arr2)
print("\nsum_col:\n{}".format(sum_col))
============================================
arr2:
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]]

sum_col:
[30 34 38 42 46]

上述代码的核心依然是einsum()方法的格式字符串,在’ij->j’中,箭头之前的输入格式字符串由两个字符构成,说明这是一个二维张量,这和arr的特征是一致的。它已经变成一个4行5列的矩阵。按照字符出现的顺序,第一个字符“i”表示行,第二个字符“j”表示列,如前面的介绍,箭头之后的格式字符“j”表示输出变量的形态,可以发现两个变化:第一,字符数量减少为1个,这说明输出变量被“降维”了;第二,原来的字符“j”被保留,它原来的位置表示列,这说明“行”这个维度被消灭了。于是,放在一起,它的效果就是通过求和的方式达到维度约减。用学术点的话来说,上述操作实现了按列求和.

sum_row = np.einsum("ab->a", arr2)
print("\nsum_row:\n{}".format(sum_row))
============================================
sum_row:
[10 35 60 85]

在上面的代码中,我们故意把格式字符串变化为"ab->a",就是想告诉你,在格式字符串中用什么字符并不重要,重要的是它们的长度,以及它们是否在箭头之后出现。上述格式字符串完全等价于"ij->i"。类似前面的分析,In [10]处实现的功能依然是通过求和进而降维。所不同的是,第一个字符a(代表行)保留,而第二个字符b(代表列)消失,这个格式表明,这是一个按行求和操作.

前面仅仅提到了利用einsum()求和,实际上,该方法的功能远不止于此。我们还可以利用它实现矩阵乘法,因为矩阵乘法涉及求和。

A = np.array([[1, 1, 1], [2, 2, 2], [5, 5, 5]])
B = np.array([[0, 1, 0], [1, 1, 0], [1, 1, 1]])
result = A @ B
print("\nresult:\n{}".format(result))
result2 = np.einsum('ij, jk->ik', A, B)
print("\nresult2:\n{}".format(result2))
===============================================
result:
[[ 2  3  1]
 [ 4  6  2]
 [10 15  5]]

result2:
[[ 2  3  1]
 [ 4  6  2]
 [10 15  5]]

利用einsum()做矩阵乘法,关键还是在于格式字符串。在上述代码的In [17]处,数组A对应的格式字符串为“ij”,字符长度为2,说明它是二维数组。类似地,二维数组B对应的格式字符串为“jk”,它们有相同的字符“j”。根据“j”出现的顺序,它表明第一个数组A的列和第二个数组B的行是相同的。但通过计算的结果发现,格式字符串中的箭头之后少了“j”的身影,这表明通过求和计算将“j”降维了,只有矩阵乘法才有类似的功效.

向量乘积

我们想求得两个向量(向量a和向量a)的中对应元素的乘积(Element-wisemultiplication),即对向量实施点乘操作,根据前面所讲,可以有两种写法:a*b或np.multiply(a,b)。学习了einsum()之后,还可以有第三种方法

a = np.array([[1, 2], [3, 4]])
b = np.ones(shape=(2, 2))
print("\narray:\n{}".format(np.einsum('ij,ij->ij', a, b)))
====================================================
array:
[[1. 2.]
 [3. 4.]]

向量内积

如果向量a和向量b是一维向量,则可写成np.einsum(‘i,i->i’,a,b)。
求向量a和向量b的内积时,可用np.inner(a, b)实现,也可以用einsum()轻易实现。

print(np.einsum('ij,ij->', a, b))
======================
10.0

矩阵的对角线

AA = np.array([[11, 12, 13, 14],
               [21, 22, 23, 24],
               [31, 32, 33, 34],
               [41, 42, 43, 44]])
print("\narray:\n{}".format(np.einsum('ii->i', AA)))
===========================================
array:
[11 22 33 44]

矩阵的迹

print(np.einsum('ii->', AA))
===================================
110

矩阵的转置

print(np.einsum('ij->ji', AA))
========================================
[[11 21 31 41]
 [12 22 32 42]
 [13 23 33 43]
 [14 24 34 44]]

完整代码

import numpy as np

arr = np.arange(10)
print("\narr: \n{}".format(arr))
sum1 = np.einsum('i->', arr)
print("\nsum1: {}".format(sum1))

arr2 = np.arange(20).reshape(4, 5)
print("\narr2:\n{}".format(arr2))
sum_col = np.einsum('ij->j', arr2)
print("\nsum_col:\n{}".format(sum_col))

sum_row = np.einsum("ab->a", arr2)
print("\nsum_row:\n{}".format(sum_row))

A = np.array([[1, 1, 1], [2, 2, 2], [5, 5, 5]])
B = np.array([[0, 1, 0], [1, 1, 0], [1, 1, 1]])
result = A @ B
print("\nresult:\n{}".format(result))
result2 = np.einsum('ij, jk->ik', A, B)
print("\nresult2:\n{}".format(result2))

a = np.array([[1, 2], [3, 4]])
b = np.ones(shape=(2, 2))
print("\narray:\n{}".format(np.einsum('ij,ij->ij', a, b)))

print(np.einsum('ij,ij->', a, b))

AA = np.array([[11, 12, 13, 14],
               [21, 22, 23, 24],
               [31, 32, 33, 34],
               [41, 42, 43, 44]])
print("\narray:\n{}".format(np.einsum('ii->i', AA)))

print(np.einsum('ii->', AA))
print(np.einsum('ij->ji', AA))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Python的NumPy库中,可以使用numpy.sum()函数来算数组元素的和。该函数的语法如下:numpy.sum(a, axis=None, dtype=None, out=None, keepdims=, initial=)。其中,参数a表示要求和的数组,axis表示求和的维度,默认为None表示对整个数组求和,dtype表示返回结果的数据类型,out表示存储结果的数组,keepdims表示保持原数组的维度,initial表示初始值。通过调用numpy.sum()函数,可以方便地计算数组的和。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【numpy求和numpy.sum()求和](https://blog.csdn.net/u014636245/article/details/84181868)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [python NumPy ndarray二维数组 按照行列求平均实例](https://download.csdn.net/download/weixin_38655767/14915707)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [python数据分析numpy](https://blog.csdn.net/m0_53068976/article/details/126715100)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZhShy23

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值