NumPy 数值计算基础

标签: #Python #NumPy #数值计算 #ndarray #广播机制 #线性代数
学习周期:2 天 | 核心目标:掌握 NumPy 多维数组的创建、索引、运算及广播机制,为数据分析和机器学习打下基础


4.1 NumPy(数值计算)

NumPy(Numerical Python)是 Python 科学计算的核心库,提供了高性能的多维数组对象 ndarray 和丰富的数组运算函数。几乎所有数据分析和机器学习库(如 Pandas、Scikit-learn、TensorFlow)都基于 NumPy。

核心优势:高速度(底层 C 语言实现)、高内存效率、丰富的数值运算功能。

安装与导入

pip install numpy
import numpy as np

4.1.1 ndarray 多维数组的创建与属性(shape, dtype)

1. 创建数组

从列表/元组创建
# 一维数组
arr1 = np.array([1, 2, 3, 4, 5])

# 二维数组(列表嵌套)
arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# 指定数据类型
arr_float = np.array([1, 2, 3], dtype=np.float64)
arr_int = np.array([1, 2, 3], dtype=np.int32)
内置创建函数(常用)
函数 说明 示例
np.zeros(shape) 全0数组 np.zeros((2,3))
np.ones(shape) 全1数组 np.ones((3,2), dtype=np.int32)
np.eye(N) 单位矩阵(N×N) np.eye(3)
np.full(shape, value) 填充指定值 np.full((2,3), 7)
np.arange(start, stop, step) 等差数列(类似 range) np.arange(0, 10, 2) → [0,2,4,6,8]
np.linspace(start, stop, num) 等间隔序列 np.linspace(0, 1, 5) → [0.,0.25,0.5,0.75,1.]
np.random.rand(d0,d1) [0,1) 均匀分布 np.random.rand(2,3)
np.random.randn(d0,d1) 标准正态分布 np.random.randn(2,3)
np.random.randint(low, high, size) 随机整数 np.random.randint(0, 10, (2,3))

2. 数组属性

arr = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float64)

print(arr.shape)      # (2, 3) → 2行3列
print(arr.ndim)       # 2 → 维度数
print(arr.size)       # 6 → 元素总数
print(arr.dtype)      # float64 → 数据类型
print(arr.itemsize)   # 8 → 每个元素字节数

# 改变形状(不改变原数组,返回新数组)
arr_reshape = arr.reshape((3, 2))

易错点

  • np.array() 中的元素类型必须一致,否则会自动向上转换(如 int + float → float)。
  • reshape() 新形状的元素总数必须与原数组相同。
  • 一维数组的 shape 是 (n,),注意末尾逗号。

4.1.2 索引、切片、布尔索引、花式索引

基础索引(按位置)

arr1 = np.arange(10)
print(arr1[3])        # 3
print(arr1[-1])       # 9

arr2 = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(arr2[0,0])      # 1
print(arr2[1,2])      # 6
print(arr2[2])        # [7,8,9](整行)

切片(范围取值)

# 一维切片
arr1 = np.arange(10)
print(arr1[2:5])      # [2,3,4]
print(arr1[::2])      # [0,2,4,6,8]

# 二维切片
arr2 = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(arr2[:2, :2])   # [[1,2],[4,5]]
print(arr2[:, 1])     # [2,5,8](第2列)
print(arr2[1, :])     # [4,5,6](第2行)

# ⚠️ 切片返回视图,修改会影响原数组
slice_view = arr2[:2, :2]
slice_view[0,0] = 100
print(arr2[0,0])      # 变为100

布尔索引(条件筛选)

arr = np.array([[1,2,3],[4,5,6],[7,8,9]])
mask = arr > 5
print(mask)           # 布尔数组
print(arr[mask])      # [6,7,8,9]

# 多条件(& 且,| 或,注意括号)
print(arr[(arr > 3) & (arr < 8)])   # [4,5,6,7]
print(arr[(arr == 2) | (arr == 8)]) # [2,8]

花式索引(整数列表索引)

arr1 = np.arange(10)
indices = [1,3,5,7]
print(arr1[indices])   # [1,3,5,7]

arr2 = np.array([[1,2,3],[4,5,6],[7,8,9]])
row = [0,2]; col = [1,2]
print(arr2[row, col])  # [2,9](取(0,1)和(2,2))

print(arr2[[0,2], :])  # 取第1行和第3行的所有列

索引方式对比

方式 返回类型 是否影响原数组
基础索引 标量或子数组 修改影响原数组
切片 视图(view) 修改影响原数组
布尔索引 副本(copy) 修改不影响原数组
花式索引 副本(copy) 修改不影响原数组

4.1.3 广播机制(Broadcasting)

广播允许不同形状的数组进行算术运算,无需手动调整形状。

核心规则(从尾部维度对齐):

  1. 维度较少的数组在前面补1。
  2. 每个维度上,两个数组的形状要么相等,要么其中一个为1,要么缺失。
  3. 满足条件则可广播;否则报错 ValueError
# 标量与数组
arr = np.array([1,2,3])
print(arr + 10)          # [11,12,13]

# 一维 + 二维
a = np.array([[1,2,3],[4,5,6]])   # (2,3)
b = np.array([10,20,30])          # (3,) → 广播为 (1,3) → (2,3)
print(a + b)                       # 每行加 b

# 列向量广播
col = np.array([[1],[2],[3]])     # (3,1)
row = np.array([10,20,30])        # (3,) → (1,3)
print(col + row)                   # (3,3)

# 不兼容示例
# a = np.ones((3,2)); b = np.ones((4,)) → ValueError

4.1.4 通用函数(ufunc)

通用函数对数组逐元素高效运算,底层 C 实现,速度极快。

数学函数

arr = np.array([1,4,9,16])

print(np.sqrt(arr))      # [1.,2.,3.,4.]
print(np.exp(arr))       # e^x
print(np.log(arr))       # 自然对数
print(np.log10(arr))     # 以10为底
print(np.sin(arr))       # 正弦(弧度)
print(np.cos(arr))
print(np.abs([-1,-2]))   # [1,2]
print(np.ceil(3.2))      # 4.0
print(np.floor(3.9))     # 3.0

二元通用函数

a = np.array([1,2,3])
b = np.array([4,5,6])

print(np.add(a,b))       # [5,7,9]
print(np.maximum(a,b))   # [4,5,6]
print(np.minimum(a,b))   # [1,2,3]
print(np.power(a,2))     # [1,4,9]

比较函数

print(np.greater(a,b))   # [False,False,False]
print(np.equal(a,b))     # [False,False,False]

4.1.5 数组运算

元素级算术运算

a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])

print(a + b)      # 加法
print(a - b)      # 减法
print(a * b)      # 逐元素乘法(不是矩阵乘法)
print(a / b)      # 除法
print(a ** 2)     # 逐元素平方

矩阵乘法

# 方式1:@ 运算符(推荐)
print(a @ b)

# 方式2:np.dot()
print(np.dot(a, b))

# 方式3:np.matmul()
print(np.matmul(a, b))

# 一维数组点积
x = np.array([1,2,3])
y = np.array([4,5,6])
print(np.dot(x, y))   # 1*4+2*5+3*6=32

统计方法

arr = np.array([[1,2,3],[4,5,6],[7,8,9]])

print(arr.sum())           # 45(总和)
print(arr.sum(axis=0))     # [12,15,18](按列求和)
print(arr.sum(axis=1))     # [6,15,24](按行求和)

print(arr.mean())          # 5.0
print(arr.mean(axis=0))    # [4.,5.,6.]

print(arr.std())           # 标准差
print(arr.var())           # 方差
print(arr.max())           # 9
print(arr.min())           # 1
print(arr.argmax(axis=0))  # 每列最大值的行索引 [2,2,2]

print(np.median(arr))      # 5.0(中位数)
print(arr.cumsum())        # 累积和 [1,3,6,10,15,21,28,36,45]

axis 参数理解

  • axis=0:沿着行方向(垂直),对每一列操作
  • axis=1:沿着列方向(水平),对每一行操作

4.1.6 线性代数基础(np.linalg

import numpy as np
from numpy import linalg as LA

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# 矩阵乘法
C = A @ B

# 转置
print(A.T)            # [[1,3],[2,4]]

# 逆矩阵(仅方阵)
A_inv = LA.inv(A)
print(A @ A_inv)      # 近似单位矩阵

# 行列式
det = LA.det(A)       # -2.0

# 迹(对角线之和)
trace = np.trace(A)   # 5

# 特征值和特征向量
eigenvalues, eigenvectors = LA.eig(A)

# 解线性方程组 Ax = b
A_eq = np.array([[3,1],[1,2]])
b_eq = np.array([9,8])
x = LA.solve(A_eq, b_eq)   # [2.,3.]

# 矩阵的秩
rank = LA.matrix_rank(A)   # 2

# 最小二乘法(拟合)
# x_lsq, residuals, rank, s = LA.lstsq(A, b, rcond=None)

注意事项

  • 求逆和行列式仅适用于方阵,非方阵会报错。
  • 若矩阵奇异(行列式为0),inv() 会抛出 LinAlgError
  • solve() 要求系数矩阵满秩,否则用 lstsq()

📚 学习资料(Obsidian 可直接收藏)


🎯 学习建议(2 天计划)

  1. 第 1 天:掌握 ndarray 创建、属性、基本索引和切片,重点练习布尔索引和花式索引,理解广播机制。
  2. 第 2 天:学习通用函数、数组运算(矩阵乘法、统计方法),了解 np.linalg 常用线性代数函数。

✅ 核心要点总结

  1. ndarray:同质多维数组,核心属性 shapedtypendimsize
  2. 创建方式np.array()np.zeros()np.ones()np.arange()np.linspace()np.random.rand() 等。
  3. 索引与切片:基本索引、切片(返回视图)、布尔索引(返回副本)、花式索引(返回副本)。
  4. 广播机制:形状兼容的数组可直接运算,自动扩展维度,规则清晰。
  5. 通用函数(ufunc)np.sqrt()np.exp()np.sin() 等,逐元素高效计算。
  6. 数组运算:元素级算术运算;矩阵乘法用 @ 或 np.dot();统计方法可指定 axis
  7. 线性代数np.linalg 提供逆、行列式、特征值、解方程组等。

练习题(自测)

  1. 创建一个 5×5 的随机整数矩阵(范围 0-100),计算其均值、标准差、最大值和最小值。
  2. 创建两个 3×3 矩阵 A 和 B,计算 A + BA - BA @ B 以及 A 的转置。
  3. 使用布尔索引将数组中所有大于 5 的元素替换为 0。
  4. 创建一个形状为 (4, 3) 的数组,通过广播将每一行都减去该行的平均值(实现行中心化)。
  5. 解线性方程组:
    2x + y = 5
    x - 3y = -1
    
  6. 生成 1000 个服从正态分布的随机数,计算其均值和标准差,并绘制直方图(可使用 Matplotlib,选做)。

建议在 Jupyter Notebook 中逐步练习,观察数组形状和广播行为。

更多推荐