← 返回首页
🧮

NumPy进阶:广播、线性代数、随机数与性能

📂 python ⏱ 3 min 490 words

NumPy进阶:广播、线性代数、随机数与性能

在掌握NumPy基础之后,本文将带你深入了解广播机制、线性代数运算、随机数生成以及性能优化等进阶主题,帮助你编写更高效、更优雅的数值计算代码。

广播机制

广播(Broadcasting)是NumPy中强大的特性,允许不同形状的数组进行算术运算,无需显式复制数据。规则如下:

  1. 两个数组的维度从右向左逐一比较
  2. 维度大小相等或其中一个为1时可以兼容
  3. 缺失的维度视为1
import numpy as np

# 标量与数组运算(自动广播)
arr = np.array([[1, 2, 3], [4, 5, 6]])
result = arr + 10
print(result)
# [[11 12 13]
#  [14 15 16]]

# 行向量与矩阵
row = np.array([10, 20, 30])
print(arr + row)
# [[11 22 33]
#  [14 25 36]]

# 列向量与矩阵
col = np.array([[100], [200]])
print(arr + col)
# [[101 102 103]
#  [204 205 206]]

# 计算每个样本与均值的差值
data = np.array([[1, 2, 3],
                 [4, 5, 6],
                 [7, 8, 9]])

mean = data.mean(axis=0)  # 按列求均值 [4. 5. 6.]
centered = data - mean    # 广播减去均值
print(centered)
# [[-3. -3. -3.]
#  [ 0.  0.  0.]
#  [ 3.  3.  3.]]

线性代数运算

NumPy的linalg模块提供了丰富的线性代数函数:

import numpy as np

# 矩阵乘法
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# 三种等价方式
C = np.dot(A, B)
C = A @ B
C = np.matmul(A, B)
print(C)
# [[19 22]
#  [43 50]]

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

# 行列式
det = np.linalg.det(A)
print(f"行列式: {det}")   # -2.0

# 逆矩阵
inv = np.linalg.inv(A)
print(f"逆矩阵:\n{inv}")

# 特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(A)
print(f"特征值: {eigenvalues}")
print(f"特征向量:\n{eigenvectors}")

# 求解线性方程组 Ax = b
b = np.array([5, 11])
x = np.linalg.solve(A, b)
print(f"解: {x}")
# 验证
print(f"验证: {A @ x}")  # [5. 11.]

# SVD奇异值分解
U, S, Vt = np.linalg.svd(A)
print(f"奇异值: {S}")

# 矩阵范数
norm = np.linalg.norm(A)
print(f"Frobenius范数: {norm:.4f}")

随机数生成

NumPy的随机数模块支持多种概率分布,是模拟和统计分析的基础:

import numpy as np

# 基础随机数
rng = np.random.default_rng(seed=42)

# 均匀分布 [0, 1)
uniform = rng.random((3, 3))
print("均匀分布:\n", uniform)

# 正态分布
normal = rng.normal(loc=0, scale=1, size=(3, 3))
print("正态分布:\n", normal)

# 整数随机
integers = rng.integers(0, 100, size=(3, 4))
print("随机整数:\n", integers)

# 随机选择
choices = rng.choice([10, 20, 30, 40, 50], size=3, replace=False)
print("不重复随机选择:", choices)

# 打乱数组
arr = np.arange(10)
rng.shuffle(arr)
print("打乱后:", arr)

# 常用分布
beta = rng.beta(2, 5, size=100)       # Beta分布
chi2 = rng.chisquare(3, size=100)      # 卡方分布
poisson = rng.poisson(lam=5, size=100) # 泊松分布

# 设置种子保证可重复性
rng1 = np.random.default_rng(seed=123)
rng2 = np.random.default_rng(seed=123)
print(rng1.random(3) == rng2.random(3))  # True

性能优化技巧

NumPy的性能优势需要正确使用才能充分发挥:

import numpy as np
import time

# 避免Python循环,使用向量化
def slow_sum(n):
    result = 0
    for i in range(n):
        result += i
    return result

def fast_sum(n):
    return np.sum(np.arange(n))

# 性能对比
n = 10_000_000

start = time.time()
slow_sum(n)
print(f"循环方式: {time.time()-start:.4f}秒")

start = time.time()
fast_sum(n)
print(f"向量化: {time.time()-start:.4f}秒")

# 预分配内存而非动态扩展
def bad_append(n):
    arr = np.array([])
    for i in range(n):
        arr = np.append(arr, i)
    return arr

def good_prealloc(n):
    arr = np.empty(n)
    for i in range(n):
        arr[i] = i
    return arr

# 使用视图而非复制
arr = np.arange(100)
view = arr[::2]     # 视图,不复制数据
copy = arr[::2].copy()  # 显式复制

# 就地操作减少内存分配
a = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
np.add(a, 1.0, out=a)   # 就地加法

结构化数组

结构化数组允许创建类似数据库表的数据结构:

import numpy as np

# 定义结构化数据类型
dt = np.dtype([('name', 'U10'), ('age', 'i4'), ('salary', 'f8')])

# 创建结构化数组
employees = np.array([
    ('Alice', 30, 75000.0),
    ('Bob', 25, 65000.0),
    ('Charlie', 35, 85000.0),
], dtype=dt)

print(employees['name'])     # ['Alice' 'Bob' 'Charlie']
print(employees['salary'])   # [75000. 65000. 85000.]

# 按条件筛选
high_salary = employees[employees['salary'] > 70000]
print(f"高薪员工: {high_salary['name']}")

实战:蒙特卡洛模拟估算π

import numpy as np

def estimate_pi(n_samples):
    rng = np.random.default_rng(seed=42)
    x = rng.random(n_samples)
    y = rng.random(n_samples)
    
    # 判断点是否在单位圆内
    inside = x**2 + y**2 <= 1
    
    # π ≈ 4 * (圆内点数 / 总点数)
    pi_estimate = 4 * np.sum(inside) / n_samples
    return pi_estimate

# 不同样本量的估算
for n in [1000, 10000, 100000, 1000000]:
    pi_est = estimate_pi(n)
    error = abs(pi_est - np.pi)
    print(f"样本数: {n:>10}, 估算π: {pi_est:.6f}, 误差: {error:.6f}")

总结

掌握NumPy的进阶特性——广播、线性代数、随机数和性能优化——能让你在数据科学工作中事半功倍。记住:优先使用向量化操作,避免不必要的循环和数据复制。