NumPy 进阶 — 矩阵、随机数与线性代数
🕐 预计用时:2-3 小时 | 🎯 目标:掌握矩阵运算、随机数生成、统计函数和线性代数操作
📖 今日目录
1. 矩阵运算
import numpy as np# 矩阵乘法(线性代数中的乘法,不是逐元素)A = np.array([[1, 2], [3, 4]])B = np.array([[5, 6], [7, 8]])# 方法1:@ 运算符(推荐)C = A @ B# [[19 22]# [43 50]]# 方法2:np.dot()C = np.dot(A, B)# 方法3:.dot() 方法C = A.dot(B)# 逐元素乘法(注意区分!)A * B# [[ 5 12]# [21 32]]
| | |
|---|
| A * B | |
| A @ B | |
| A.T | |
| np.linalg.inv(A) | |
| np.linalg.det(A) | |
# 矩阵的其他操作A = np.array([[1, 2], [3, 4]])np.linalg.inv(A) # 逆矩阵np.linalg.det(A) # 行列式 → -2.0np.trace(A) # 迹(对角线之和)→ 5np.linalg.matrix_rank(A) # 秩 → 2# 特征值与特征向量eigenvalues, eigenvectors = np.linalg.eig(A)print(eigenvalues) # [-0.37 5.37]print(eigenvectors)
2. 随机数生成
import numpy as np# 设置随机种子(可复现)np.random.seed(42)# 均匀分布 [0, 1)np.random.random(5) # 5 个 0-1 的随机数np.random.random((3, 3)) # 3x3 矩阵# 随机整数np.random.randint(1, 100, 5) # 5 个 1-99 的随机整数np.random.randint(1, 100, (3, 4)) # 3x4 矩阵# 正态分布(高斯分布)np.random.randn(5) # 标准正态分布(均值0,标准差1)np.random.randn(3, 3) # 3x3 矩阵np.random.normal(100, 15, 5) # 均值100,标准差15(模拟考试成绩)# 随机选择arr = np.array([10, 20, 30, 40, 50])np.random.choice(arr, 3) # 从 arr 中随机选 3 个np.random.choice(arr, 3, replace=False) # 不重复抽样np.random.choice(arr, (2, 3)) # 2x3 矩阵# 随机打乱deck = np.arange(52)np.random.shuffle(deck) # 原地打乱(修改原数组)print(deck)# 随机排列(返回新数组)np.random.permutation(10) # 0-9 的随机排列
💡 随机种子的重要性:np.random.seed(42) 设置种子后,每次运行生成的随机数相同——这对实验复现至关重要。在机器学习中,固定种子可以确保:每次训练结果一致,方便调试。
📌 NumPy 2.0+ 推荐写法:上面使用的 np.random.seed() 和 np.random.randn() 属于旧版 RandomState API,仍可使用但官方推荐改用新的 Generator API:rng = np.random.default_rng(42)rng.random(5)rng.normal(0, 1, 5)rng.integers(1, 100, 5)新 API 速度更快、分布更优,且每个 rng 对象独立管理种子,避免全局污染。
📋 常用分布
| | |
|---|
| np.random.uniform(a, b) | |
| np.random.normal(μ, σ) | |
| np.random.binomial(n, p) | |
| np.random.poisson(λ) | |
| np.random.exponential(β) | |
3. 统计函数
import numpy as npnp.random.seed(42)scores = np.random.normal(70, 15, (5, 3)) # 5 个学生,3 门课# 模拟成绩:均值70,标准差15# 基础统计np.mean(scores) # 全体均值np.mean(scores, axis=0) # 每门课的均值(按列)np.mean(scores, axis=1) # 每个学生的均值(按行)np.median(scores) # 中位数np.std(scores) # 标准差np.var(scores) # 方差np.ptp(scores) # 极差(最大值 - 最小值)# 分位数np.percentile(scores, 25) # 第一四分位数(25%)np.percentile(scores, 50) # 中位数(50%)np.percentile(scores, 75) # 第三四分位数(75%)# 相关系数矩阵# 3 门课之间的相关性np.corrcoef(scores.T) # 3x3 相关系数矩阵# 协方差矩阵np.cov(scores.T) # 3x3 协方差矩阵# 直方图统计data = np.random.normal(0, 1, 1000)counts, bins = np.histogram(data, bins=10)print(f'区间: {bins}')print(f'频数: {counts}')
4. 线性代数
import numpy as npfrom numpy import linalg as LA# 解线性方程组# 2x + 3y = 8# 3x + 4y = 11A = np.array([[2, 3], [3, 4]])b = np.array([8, 11])x = LA.solve(A, b)print(x) # [1. 2.] → x=1, y=2# 验证print(A @ x) # [8. 11.] ✅# 向量范数(长度)v = np.array([3, 4])LA.norm(v) # 5.0(L2范数,默认)LA.norm(v, 1) # 7.0(L1范数,绝对值之和)LA.norm(v, np.inf) # 4.0(无穷范数,最大绝对值)# 矩阵范数A = np.array([[1, 2], [3, 4]])LA.norm(A, 'fro') # Frobenius 范数# 矩阵分解# SVD 分解(奇异值分解)U, S, Vt = LA.svd(A)print(f'U: {U.shape}, S: {S.shape}, Vt: {Vt.shape}')# QR 分解Q, R = LA.qr(A)# Cholesky 分解(正定矩阵)# LA.cholesky(A) # A 必须是正定矩阵# 求解 Ax = b 的最小二乘解(超定方程组)A = np.array([[1, 1], [1, 2], [1, 3]])b = np.array([1, 2, 2.5])x, residuals, rank, sv = LA.lstsq(A, b, rcond=None)print(x) # 最小二乘解
5. 数组变形与拼接
import numpy as np# === 变形 ===arr = np.arange(12)arr.reshape(3, 4) # 3x4arr.reshape(4, 3) # 4x3arr.reshape(2, -1) # 2行,列自动算 → 2x6arr.reshape(-1, 6) # 列6,行自动算 → 2x6arr.reshape(2, 3, 2) # 三维 2x3x2# 展平arr2d = np.array([[1,2,3],[4,5,6]])arr2d.flatten() # [1 2 3 4 5 6](返回副本)arr2d.ravel() # [1 2 3 4 5 6](返回视图)arr2d.reshape(-1) # [1 2 3 4 5 6](返回视图)# === 拼接 ===a = np.array([1, 2, 3])b = np.array([4, 5, 6])# 水平拼接(列方向)np.hstack([a, b]) # [1 2 3 4 5 6]np.concatenate([a, b]) # [1 2 3 4 5 6](同上)# 垂直拼接(行方向)np.vstack([a, b])# [[1 2 3]# [4 5 6]]# 二维拼接A = np.array([[1, 2], [3, 4]])B = np.array([[5, 6], [7, 8]])np.concatenate([A, B], axis=0) # 按行拼 → 4x2np.concatenate([A, B], axis=1) # 按列拼 → 2x4# === 分割 ===arr = np.arange(12)np.split(arr, 3) # 均分为3份 → [0,1,2,3], [4,5,6,7], [8,9,10,11]np.split(arr, [3, 7]) # 在索引3和7处分割 → [0,1,2], [3,4,5,6], [7,8,9,10,11]np.hsplit(arr2d, 3) # 水平分割(列方向)np.vsplit(arr2d, 2) # 垂直分割(行方向)
6. 文件读写
import numpy as np# === 二进制格式(推荐,速度快)===arr = np.array([[1, 2, 3], [4, 5, 6]])# 保存为 .npy 文件np.save('data.npy', arr)loaded = np.load('data.npy')# 保存多个数组为 .npz 文件np.savez('data.npz', a=arr, b=arr*2)data = np.load('data.npz')print(data['a'])print(data['b'])# === 文本格式(可读性好)===arr = np.array([[1, 2, 3], [4, 5, 6]])# 保存为文本np.savetxt('data.txt', arr, fmt='%d', delimiter=',')loaded = np.loadtxt('data.txt', delimiter=',')# 从 CSV 读取# np.genfromtxt('data.csv', delimiter=',', skip_header=1)
7. 性能优化技巧
import numpy as npimport time# 技巧1:避免 Python 循环,用向量化# ❌ 慢def slow_mean(arr): total = 0 for x in arr: total += x return total / len(arr)# ✅ 快def fast_mean(arr): return np.mean(arr)# 技巧2:预分配数组,避免动态增长# ❌ 慢(不断拼接新数组)result = np.array([])for i in range(1000): result = np.append(result, i) # 每次创建新数组!# ✅ 快(预分配)result = np.zeros(1000)for i in range(1000): result[i] = i# 技巧3:用 np.where 替代条件循环# ❌ 慢result = []for x in arr: if x > 0: result.append(x) else: result.append(0)# ✅ 快result = np.where(arr > 0, arr, 0)# 技巧4:就地操作(避免创建副本)# ❌ 创建新数组arr = arr + 1# ✅ 就地修改arr += 1# 技巧5:用广播替代循环# ❌ 双重循环for i in range(n): for j in range(m): C[i,j] = A[i] * B[j]# ✅ 广播C = A[:, np.newaxis] * B[np.newaxis, :]
8. 今日练习
🏋️ 练习 1:矩阵运算
# 解方程组:# x + 2y + 3z = 1# 2x + 5y + 2z = 3# 6x - 3y + z = 2# 用 LA.solve() 求解
🏋️ 练习 2:随机模拟
# 用 NumPy 模拟抛硬币实验:# 抛 1000 次,每次抛 10 个硬币# 统计正面朝上的次数分布# 画出直方图(用 np.histogram)
🏋️ 练习 3:图像处理
# 用 NumPy 模拟图像操作:# 创建一个 10x10 的灰度图矩阵(0-255)# 实现:亮度+50、对比度翻转、裁剪中心区域、水平翻转
9. 今日小结
| |
|---|
| A @ B 矩阵乘法 / .T 转置 / inv 求逆 / det 行列式 |
| random / randint / randn / normal / choice / seed |
| mean / std / median / percentile / corrcoef / histogram |
| solve / norm / svd / qr / lstsq |
| reshape / flatten / hstack / vstack / concatenate / split |
| save / load / savez / savetxt / loadtxt |
| 向量化 / 预分配 / np.where / 就地操作 / 广播 |
🚀 明日预告:Day 73 — Pandas 基础Series 和 DataFrame——数据分析师的 Excel 替代品。读取 CSV、查看数据、基础索引,数据科学的核心工具即将登场!