python:Numpy

发布于:2025-03-12 ⋅ 阅读:(16) ⋅ 点赞:(0)

Numpy的核心要点

1.理解NumPy的核心对象——ndarray

核心特性
  • 多维容器:可表示向量(1D)、矩阵(2D)、张量(3D+)。
  • 同构数据类型:所有元素类型相同(如 int32float64)。
  • 高效内存管理:数据存储在连续内存块中,避免指针开销。
  • 向量化操作:无需循环即可对整个数组进行数学运算。
关键属性
  • shape:各维度大小的元组(如(2,3))
  • dtype:元素类型(如float64、int32)
  • strides:每个维度步长的字节数(内存布局)
print(arr.shape)   # (2, 2)
print(arr.dtype)    # int32 (默认类型)
import numpy as np

# 创建数组
arr = np.array([[1, 2, 3], [4, 5, 6]])  # 2x3矩阵
print("维度:", arr.ndim)     # 2
print("形状:", arr.shape)    # (2, 3)
print("数据类型:", arr.dtype) # int32

2.数组创建与初始化 

常用方法
方法 说明 示例
np.array() 从Python列表/元组创建 np.array([1, 2, 3])
np.zeros() 全零数组 np.zeros((2, 3))
np.ones() 全一数组 np.ones((3, 2), dtype=float)
np.arange() 等差数列 np.arange(0, 10, 2) → [0,2,4,6,8]
np.linspace() 等分区间 np.linspace(0, 1, 5) → [0.0, 0.25, 0.5, 0.75, 1.0]
np.random 生成随机数组 np.random.randn(3, 3) 生成标准正态分布数组
随机数组生成
# 生成0~1均匀分布的3x3矩阵
rand_arr = np.random.rand(3, 3)

# 生成标准正态分布的10个样本
normal_arr = np.random.randn(10)

3. 数组操作与变形

形状操作
arr = np.arange(6)  # [0,1,2,3,4,5]

# 变形为 2x3 矩阵
reshaped = arr.reshape(2, 3)

# 展平为 1D 数组
flattened = reshaped.flatten()

# 转置矩阵
transposed = reshaped.T

# 自动推导维度
reshaped = arr.reshape(3, -1)  # -1表示自动计算该维度大小
合并与拆分
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])

# 垂直拼接(按行)
v_stack = np.vstack([a, b])  # 结果形状:(3, 2)

# 水平拆分(按列)
split_arr = np.hsplit(a, 2)  # 得到两个数组 [array([[1], [3]]), array([[2], [4]])]

 4.矢量化运算(无需循环)

 矢量化(Vectorization)指直接对整个数组进行数学运算,​无需显式编写循环。NumPy通过底层C代码实现高效批量操作,利用CPU的SIMD指令并行处理数据。

核心优势

  • 代码简洁:用一行代码替代多层循环。
  • 性能卓越:比Python循环快10~100倍。
  • 可读性强:更贴近数学公式的表达方式。
元素级运算
arr = np.array([1, 2, 3])

# 平方运算(无需循环)
squared = arr ​** 2  # [1, 4, 9]

# 三角函数
sin_values = np.sin(arr)
矩阵运算
A = np.array([[1,2], [3,4]])
B = np.array([[5,6], [7,8]])

# 矩阵乘法
dot_product = A @ B  # 或 np.dot(A, B)
# 结果:[[19, 22], [43, 50]]

# 逐元素乘法
elementwise = A * B  # [[5, 12], [21, 32]]

 最佳实践总结

操作 推荐方法 错误示例
数组与标量运算 arr + 5 使用循环逐个元素加5
数组间逐元素操作 arr1 * arr2 嵌套循环计算每个元素乘积
条件过滤 arr[arr > 0] 循环+if判断
数学函数应用 np.sin(arr) 循环调用math.sin()

关键提示

  • 始终优先使用NumPy内置函数而非Python循环。
  • 利用广播机制简化维度不同的数组运算。
  • 处理超大数据时监控内存使用(arr.nbytes查看字节数)。

5.广播机制(Broadcasting)​

规则:(向多的看齐)
  • 从右向左对齐维度,不足的维度补1。
  • 每个维度的大小必须相等或其中一个为1。

示例

# 矩阵每行加上一个向量
matrix = np.array([[1, 2, 3], [4, 5, 6]])  # 形状 (2, 3)
vector = np.array([10, 20, 30])            # 形状 (3,)
result = matrix + vector  # 广播后结果:[[11,22,33], [14,25,36]]

运算过程

  1. vector 被广播为形状 (2,3):
    [[10, 20, 30],
     [10, 20, 30]]
  2. 逐元素相加:
    [[11, 22, 33],
     [14, 25, 36]]

广播机制(Broadcasting)规则详解

NumPy的广播机制允许不同形状的数组进行算术运算,其核心规则如下:

1. 规则解析

  1. 维度对齐:从右向左逐个维度对齐,缺失的维度自动补1。

  2. 维度兼容:每个维度的大小必须满足以下条件之一:

    • 相等

    • 其中一个为1(此时该维度扩展为另一个数组对应维度的大小)


2. 广播步骤

  1. 对齐维度:将两个数组的维度向右对齐,不足的维度补1。

  2. 检查兼容性:每个维度的大小必须相等或其中一个为1。

  3. 扩展维度:将大小为1的维度扩展为另一个数组对应维度的大小。


3. 示例与验证

示例1:形状为 (3,4) 和 (4,) 的数组相加

import numpy as np

A = np.ones((3, 4))  # 形状 (3,4)
B = np.ones((4,))     # 形状 (4,) → 对齐后补1 → (1,4)
C = A + B             # 广播后形状 (3,4)

结果:运算成功,B沿第一个维度扩展3次。

示例2:形状为 (5,4,3) 和 (4,1) 的数组相加

D = np.ones((5, 4, 3))  # 形状 (5,4,3)
E = np.ones((4, 1))     # 形状 (4,1) → 对齐后补1 → (1,4,1)
F = D + E               # 广播后形状 (5,4,3)

结果:E的三个维度分别扩展为5、4、3。

示例3:形状为 (2,3) 和 (3,2) 的数组相加

G = np.ones((2, 3))
H = np.ones((3, 2))
try:
    I = G + H  # 尝试相加
except ValueError as e:
    print("错误信息:", e)  # 输出:operands could not be broadcast together

结果:维度不兼容(3和2),触发ValueError

示例4:形状为 (3,1,5) 和 (4,1) 的数组相加

J = np.ones((3, 1, 5))  # 形状 (3,1,5)
K = np.ones((4, 1))     # 形状 (4,1) → 对齐后补1 → (1,4,1)
L = J + K               # 广播后形状 (3,4,5)

结果:K的三个维度分别扩展为3、4、5。

示例5:标量与多维数组相加

M = np.ones((2, 3))
scalar = 5              # 标量 → 视为形状 ()
N = M + scalar          # 标量广播为 (2,3)

结果:标量扩展为与M相同的形状。


4. 特殊场景与调试技巧

  1. 标量广播:标量被视为0维数组,自动补足所有维度为1。

    scalar + np.ones((5, 3, 2))  # 标量广播为 (5,3,2)
  2. 维度为1的扩展

    P = np.ones((1, 4))    # 形状 (1,4)
    Q = np.ones((3, 1))    # 形状 (3,1)
    R = P + Q              # 广播后形状 (3,4)
  3. 调试维度不匹配

    • 错误示例:形状为(3,4)(4,3)的数组相加。

    • 原因:第二个维度4和3不兼容。


5. 广播机制的内存优化

  • 虚拟扩展:广播不会实际复制数据,而是通过“虚拟视图”模拟扩展。

  • 内存高效:即使广播后的数组看似很大,内存占用仍与原数据一致。


6. 广播规则总结表

数组形状

对齐后形状

是否兼容

广播后形状

(3,4) 和 (4,)

(3,4) vs (1,4)

(3,4)

(5,4,3) 和 (4,1)

(5,4,3) vs (1,4,1)

(5,4,3)

(2,3) 和 (3,2)

(2,3) vs (3,2)

报错

(3,1,5) 和 (4,1)

(3,1,5) vs (1,4,1)

(3,4,5)

6. 高级索引

布尔索引
data = np.array([3, 1, 4, 1, 5])
mask = data > 2
filtered = data[mask]  # 输出 [3, 4, 5]
花式索引(Fancy Indexing)​:
arr = np.arange(25).reshape(5, 5)

# 选择第1行和第3行的第0列和第2列
selected = arr[[1, 3]][:, [0, 2]]  # 或直接 arr[[1,3], [0,2]]

7. 性能优化原理

为何NumPy比纯Python快?
  1. 连续内存:数据存储在连续内存块,CPU缓存利用率高。
  2. 向量化操作:用C语言实现底层循环,避免Python解释器开销。
  3. SIMD指令:单指令多数据流加速计算(如同时处理多个浮点数)。

速度对比

# Python列表求和
py_list = list(range(1_000_000))
%timeit sum(py_list)  # 约 50ms

# NumPy数组求和
np_arr = np.array(py_list)
%timeit np.sum(np_arr)  # 约 0.3ms(快约100倍)

8. 实际应用场景

数据标准化
data = np.random.randn(100, 5)  # 生成100行5列数据
mean = data.mean(axis=0)        # 计算每列均值
std = data.std(axis=0)          # 计算每列标准差
normalized = (data - mean) / std  # 标准化
解线性方程组
A = np.array([[3, 1], [1, 2]])
b = np.array([9, 8])
x = np.linalg.solve(A, b)  # 解为 [2., 3.]
图像处理
# 假设 image 是一个 100x100x3 的RGB图像数组
image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)

# 提取红色通道
red_channel = image[:, :, 0]

# 转换为灰度图像
gray_image = np.mean(image, axis=2).astype(np.uint8)

​9.核心要点总结

核心概念 关键点
ndarray 结构 多维、同构数据类型、连续内存
矢量化运算 避免Python循环,直接操作整个数组
广播机制 自动扩展不同形状数组维度,简化代码
高级索引 布尔索引、花式索引、切片(返回视图而非副本)
性能优势 内存连续 + 预编译C代码 + SIMD指令