当前位置:首页>python>我的Python100天打卡:68/100 第十八章 Numpy爱因斯坦求和约定 | 二维数组求和

我的Python100天打卡:68/100 第十八章 Numpy爱因斯坦求和约定 | 二维数组求和

  • 2026-10-11 08:29:55
我的Python100天打卡:68/100 第十八章 Numpy爱因斯坦求和约定 | 二维数组求和

#鸢尾花数学大系

挑战100天持续练习Python
今天是第68天
---

上次笔记,完成了第十七章Numpy的练习题,正式结束Numpy关于线性代数这块的知识。

今天新开第十八章Numpy爱因斯坦求和约定。按照作者的定位,这章也是略读即可。先附上思维导图和作者讲解视频:

【Chapter 17 NumPy线性代数  | 《编程不难》 | 鸢尾花书:从加减乘除到机器学习】 https://www.bilibili.com/video/BV1VD421L7Hf/

---

今天打算更一下18.1-18.2的部分:

18.1 什么是爱因斯坦求和约定
18.2 二维数组求和
---
18.1 什么是爱因斯坦求和约定核心思想
1️⃣爱因斯坦求和约定(Einstein summation convention)是一种数学表示法,由阿尔伯特·爱因斯坦于1916年提出,用于简化线性代数和张量计算中的表达式。
2️⃣NumPy中的实现
NumPy通过numpy.einsum()函数实现这一约定。
import numpy as np# 创建两个矩阵A = np.array([[1, 2], [3, 4]])B = np.array([[5, 6], [7, 8]])# 传统矩阵乘法C_traditional = A @ Bprint("传统矩阵乘法结果:")print(C_traditional)# 爱因斯坦求和约定C_einsum = np.einsum('ij,jk->ik', A, B)print("\n爱因斯坦求和约定结果:")print(C_einsum)
3️⃣常见运算表:
表18.1总结了如何使用numpy.einsum()完成常见线性代数运算
--
18.2 二维数组求和
1️⃣使用鸢尾花数据进行二维数组求和的演示代码:
import numpy as npfrom sklearn.datasets import load_iris# 加载鸢尾花数据集iris = load_iris()X = iris.data  # 形状(150, 4)print(f"鸢尾花数据集形状: {X.shape}")print(f"前5行数据:\n{X[:5]}")# 1. 所有元素求和total_sum = np.einsum('ij->', X)print(f"\n1. 所有元素总和: {total_sum:.2f}")print(f"   验证(np.sum): {np.sum(X):.2f}")# 2. 每一列求和(特征求和)col_sum = np.einsum('ij->j', X)print(f"\n2. 每一列求和:")for i, val in enumerate(col_sum):    print(f"   特征{i+1}: {val:.2f}")print(f"   验证(np.sum, axis=0): {np.sum(X, axis=0)}")# 3. 每一行求和(样本求和)row_sum = np.einsum('ij->i', X)print(f"\n3. 每一行求和(前5个样本):")for i, val in enumerate(row_sum[:5]):    print(f"   样本{i+1}: {val:.2f}")print(f"   验证(np.sum, axis=1)[:5]: {np.sum(X, axis=1)[:5]}")# 4. 提取对角线元素(对格拉姆矩阵)G = X.T @ Xdiag_elements = np.einsum('ii->i', G)print(f"\n4. 格拉姆矩阵对角线元素(特征平方和):")for i, val in enumerate(diag_elements):    print(f"   特征{i+1}平方和: {val:.2f}")# 5. 计算格拉姆矩阵的迹trace_G = np.einsum('ii->', G)print(f"\n5. 格拉姆矩阵的迹: {trace_G:.2f}")print(f"   验证(np.trace): {np.trace(G):.2f}")求和运算的可视化理解
2️⃣图18.2-18.4展示了不同方向的求和操作:
(1)图18.2 列求和:'ij->j',沿行方向(i)压缩,保留列(j)
(2)图18.3 行求和:'ij->i',沿列方向(j)压缩,保留行(i)
(3)图18.4 全求和:'ij->',压缩所有维度,输出标量
3️⃣爱因斯坦求和约定的优势
# 比较不同方法的计算效率import time# 方法1:使用循环def sum_with_loops(X):    total = 0    for i in range(X.shape[0]):        for j in range(X.shape[1]):            total += X[i, j]    return total# 方法2:使用NumPy内置函数def sum_with_numpy(X):    return np.sum(X)# 方法3:使用爱因斯坦求和def sum_with_einsum(X):    return np.einsum('ij->', X)# 测试性能X_large = np.random.randn(1000, 1000)methods = [sum_with_loops, sum_with_numpy, sum_with_einsum]names = ["循环", "NumPy", "爱因斯坦"]for func, name in zip(methods, names):    start = time.time()    result = func(X_large)    elapsed = time.time() - start    print(f"{name}方法: 结果={result:.2f}, 耗时={elapsed:.4f}秒")
---
今天的学习心得:
1️⃣爱因斯坦求和约定的实际价值
1. 感觉表达非常简洁,复杂的运算,做“调包侠”,调用别人写好的一个代码即可,不用手搓公式。比起调包侠带来的偷懒感,我更倾向于认为这是一种典型的信息差,掌握了多一个工具,就相当于掌握了多一句魔法咒语,省时省力,事半功倍。
2. 简洁的公式带来另一种优势,就是避免手搓函数的众多中间变量,降低内存的占用。
3. 如果以后需要改动,易于维护和统一处理。
2️⃣爱因斯坦求和公式的关键:索引规则
以[列求和:'ij->j']为例,这个代码撰写方法就很形象,表示沿行方向(i)压缩,保留列(j)。
这也给我很大的启发,有时候真的不需要把事情说得很复杂,化繁为简有时候恰恰能体现强大的知识功底。
3️⃣爱因斯坦求和公式在数据科学中的应用场景
特征工程:快速计算特征的统计量
降维处理:PCA中的协方差矩阵计算
相似度计算:样本间的距离和相似度
神经网络:张量运算的前向和反向传播
--
掌握了求和操作后,下一节将学习转置和矩阵乘法。
爱因斯坦求和约定真正强大的地方,在于处理高维数组和复杂张量运算,这也是深度学习框架(如PyTorch、TensorFlow)广泛采用这一约定的原因。
AI编程教练提到,可以将爱因斯坦求和约定看作"维度的乐高积木",通过组合不同的索引模式,可以构建出任意复杂的张量运算。开始可能会觉得抽象,但随着练习增加,会越来越体会到它的简洁和强大。

---

笔记写于:2026年4月24日16:37:25

结束于:2026年4月24日17:07:25

用时:约半小时

--

#鸢尾花数学大系

#编程随记

最新文章

随机文章