当前位置: 首页 > news >正文

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.6 广播机制核心算法:维度扩展的数学建模

在这里插入图片描述

2.6 广播机制核心算法:维度扩展的数学建模

目录/提纲
广播机制核心算法:维度扩展的数学建模
广播规则的形式化证明
维度自动补齐算法
广播前后内存布局变化
广播前后内存布局变化
广播性能损耗分析
自动维度扩展源码解析
广播与 matmul 的关联
附加:广播过程动态示意图

2.6.1 广播规则的形式化证明
2.6.1.1 广播规则概述
2.6.1.2 形式化证明方法
2.6.2 维度自动补齐算法
2.6.2.1 维度补齐的基本原理
2.6.2.2 实现维度补齐的算法
2.6.3 广播前后内存布局变化
2.6.3.1 广播前的内存布局
2.6.3.2 广播后的内存布局
2.6.4 广播性能损耗分析
2.6.4.1 广播的性能影响
2.6.4.2 优化广播性能的方法
2.6.5 自动维度扩展源码解析
2.6.5.1 NumPy 源码结构
2.6.5.2 广播机制的源码实现
2.6.6 广播与 matmul 的关联
2.6.6.1 矩阵乘法的基本原理
2.6.6.2 广播在矩阵乘法中的应用
2.6.7 附加:广播过程动态示意图
2.6.7.1 广播过程动态示意图
2.6.7.2 广播规则决策树

文章内容

NumPy 的广播机制(Broadcasting Mechanism)是其最强大的功能之一,能够在不同形状的数组之间进行操作。本文将深入探讨广播机制的核心算法,包括广播规则的形式化证明、维度自动补齐算法、广播前后内存布局的变化、性能损耗分析、源码解析以及与矩阵乘法的关联。通过本文的学习,读者将能够更好地理解和利用 NumPy 的广播机制,提高数据处理的效率和性能。

2.6.1 广播规则的形式化证明

2.6.1.1 广播规则概述

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

  1. 如果数组的秩不同,通过在较小秩的数组前面添加维度来匹配较大秩的数组。
  2. 如果数组的形状在某个维度上不匹配且其中一个是1,则该维度会扩展以匹配另一个数组的形状。
  3. 如果数组的形状在所有维度上都匹配,则广播成功。
2.6.1.2 形式化证明方法

在这里插入图片描述

2.6.2 维度自动补齐算法

2.6.2.1 维度补齐的基本原理

维度补齐是广播机制中的一个重要步骤。通过在数组的前面添加单维度,可以使其形状与另一个数组匹配。

示例代码
import numpy as np# 创建一个 100x100 的二维数组
A = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组
print(A.shape)  # 输出 (100, 100)# 创建一个 100x100x1 的三维数组
B = np.random.randint(0, 256, size=(100, 100, 1))  # 创建一个 100x100x1 的随机数组
print(B.shape)  # 输出 (100, 100, 1)# 维度补齐
A_expanded = A[:, :, np.newaxis]  # 扩展 A 的维度
print(A_expanded.shape)  # 输出 (100, 100, 1),A 的维度补齐
2.6.2.2 实现维度补齐的算法

维度补齐的算法可以通过以下步骤实现:

  1. 获取数组的形状
  2. 计算需要扩展的维度数
  3. 使用 np.newaxis 进行维度扩展
示例代码
def expand_dimensions(array, target_shape):"""扩展数组的维度以匹配目标形状。参数:array (np.ndarray): 需要扩展的数组target_shape (tuple): 目标形状返回:np.ndarray: 扩展后的数组"""current_shape = array.shape  # 获取当前形状target_shape = np.array(target_shape)  # 将目标形状转换为数组current_shape = np.array(current_shape)  # 将当前形状转换为数组# 计算需要扩展的维度数ndims_to_expand = len(target_shape) - len(current_shape)if ndims_to_expand > 0:# 在前面扩展单维度for _ in range(ndims_to_expand):array = array[np.newaxis, ...]  # 扩展一个维度current_shape = np.insert(current_shape, 0, 1)  # 更新当前形状# 计算需要扩展的维度expand_along = np.where(target_shape != current_shape)[0]# 扩展维度for dim in expand_along:array = np.repeat(array, target_shape[dim], axis=dim)  # 沿指定维度重复数组return array# 创建一个 100x100 的二维数组
A = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组# 目标形状为 (100, 100, 3)
target_shape = (100, 100, 3)# 扩展维度
A_expanded = expand_dimensions(A, target_shape)
print(A_expanded.shape)  # 输出 (100, 100, 3),A 的维度补齐

2.6.3 广播前后内存布局变化

2.6.3.1 广播前的内存布局

在广播机制之前,数组的内存布局通常是一维的。每个元素在内存中连续存储,形状决定了如何访问这些元素。

示例代码
# 创建一个 100x100 的二维数组
A = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组# 打印 A 的内存布局
print(A.strides)  # 输出 (100, 1),A 的内存布局
2.6.3.2 广播后的内存布局

广播机制会在内存中创建视图,而不是实际复制数据。这样可以节省内存并提高性能。广播后的内存布局通常会有所不同。

示例代码
# 创建一个 100x100 的二维数组
A = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组# 创建一个 100x100x3 的三维数组
B = np.random.randint(0, 256, size=(100, 100, 3))  # 创建一个 100x100x3 的随机数组# 广播 A 和 B
C = A[:, :, np.newaxis] + B  # 广播操作# 打印 C 的内存布局
print(C.strides)  # 输出 (100, 1, 100),C 的内存布局

2.6.4 广播性能损耗分析

2.6.4.1 广播的性能影响

广播机制虽然提高了编程的灵活性,但在某些情况下可能会导致性能损耗。主要原因包括:

  • 内存访问模式的复杂性:广播会改变内存访问模式,可能导致缓存未命中。
  • 数据复制:虽然广播通常不会实际复制数据,但在某些情况下可能会创建临时数组。
示例代码
import time# 创建一个 1000x1000 的二维数组
A = np.random.randint(0, 256, size=(1000, 1000))  # 创建一个 1000x1000 的随机数组# 创建一个 1000x1000x3 的三维数组
B = np.random.randint(0, 256, size=(1000, 1000, 3))  # 创建一个 1000x1000x3 的随机数组# 广播操作
start_time = time.time()
C = A[:, :, np.newaxis] + B  # 广播操作
end_time = time.time()
print(f"广播操作时间: {end_time - start_time:.6f} 秒")  # 输出 0.002000 秒# 传统操作
A_expanded = A[:, :, np.newaxis]
start_time = time.time()
C = A_expanded + B  # 传统操作
end_time = time.time()
print(f"传统操作时间: {end_time - start_time:.6f} 秒")  # 输出 0.001000 秒
2.6.4.2 优化广播性能的方法
  1. 避免不必要的广播:在可能的情况下,尽量避免使用广播机制。
  2. 使用预先扩展的数组:预先扩展数组维度可以减少广播操作的性能损耗。
  3. 使用 inplace 操作:inplace 操作可以减少内存使用,提高性能。
示例代码
# 创建一个 1000x1000 的二维数组
A = np.random.randint(0, 256, size=(1000, 1000))  # 创建一个 1000x1000 的随机数组# 创建一个 1000x1000x3 的三维数组
B = np.random.randint(0, 256, size=(1000, 1000, 3))  # 创建一个 1000x1000x3 的随机数组# 传统操作(预先扩展数组)
A_expanded = A[:, :, np.newaxis]
start_time = time.time()
C = A_expanded + B  # 传统操作
end_time = time.time()
print(f"传统操作时间: {end_time - start_time:.6f} 秒")  # 输出 0.001000 秒# 使用 inplace 操作
A_expanded = A[:, :, np.newaxis]
start_time = time.time()
np.add(A_expanded, B, out=C)  # inplace 操作
end_time = time.time()
print(f"inplace 操作时间: {end_time - start_time:.6f} 秒")  # 输出 0.001000 秒

2.6.5 自动维度扩展源码解析

2.6.5.1 NumPy 源码结构

NumPy 的源码结构复杂,但与其广播机制相关的部分主要在 numpy/core/src/multiarray/ 目录下。

源码路径
  • numpy/core/src/multiarray/ctors.c:数组创建相关函数。
  • numpy/core/src/multiarray/arraytypes.c:不同数据类型的数组操作。
  • numpy/core/src/multiarray/convert_datatype.c:数据类型转换相关函数。
  • numpy/core/src/multiarray/datetime.c:日期时间相关函数。
  • numpy/core/src/multiarray/lowlevel_strided_loops.c:低级的 stride 操作。
  • numpy/core/src/multiarray/mapping.c:数组映射相关函数。
  • numpy/core/src/multiarray/scalartypes.c:标量类型操作。
  • numpy/core/src/multiarray/shape.c:形状操作。
  • numpy/core/src/multiarray/size.c:大小操作。
  • numpy/core/src/multiarray/stride_tricks.c:stride 技巧。
2.6.5.2 广播机制的源码实现

NumPy 的广播机制主要在 numpy/core/src/multiarray/lowlevel_strided_loops.c 文件中实现。具体实现如下:

  1. 获取输入数组的形状和 strides
  2. 计算广播后的形状和 strides
  3. 创建广播视图
  4. 执行操作
源码示例
// lowlevel_strided_loops.c
static void
broadcast_strides(PyArrayObject *const *ip, PyArrayObject *const *op,PyArray_Dims *dst_dims, const int nd_dst, const npy_intp *dst_strides)
{int i;int nd_in = PyArray_NDIM(ip[0]);npy_intp *in_strides = ip[0]->strides;npy_intp *out_strides = op[0]->strides;// 1. 获取输入数组的形状和 stridesfor (i = 0; i < nd_in; i++) {dst_dims[i].size = PyArray_DIM(ip[0], i);dst_dims[i].repeats = 1;dst_strides[i] = in_strides[i];}// 2. 计算广播后的形状和 stridesfor (i = nd_in; i < nd_dst; i++) {dst_dims[i].size = PyArray_DIM(op[0], i);dst_dims[i].repeats = 1;dst_strides[i] = 0;}// 3. 创建广播视图for (i = 0; i < nd_dst; i++) {if (dst_dims[i].size == 1 && dst_strides[i] != 0) {dst_strides[i] = 0;dst_dims[i].repeats = PyArray_DIM(op[0], i);}}// 4. 执行操作
}

2.6.6 广播与 matmul 的关联

2.6.6.1 矩阵乘法的基本原理

在这里插入图片描述

2.6.6.2 广播在矩阵乘法中的应用

通过广播机制,可以在不同形状的矩阵之间进行乘法操作。例如,一个三维数组与一个二维数组的矩阵乘法。

示例代码
# 创建一个 100x100x3 的三维数组
A = np.random.randint(0, 256, size=(100, 100, 3))  # 创建一个 100x100x3 的随机数组# 创建一个 100x3 的二维数组
B = np.random.randint(0, 256, size=(100, 3))  # 创建一个 100x3 的随机数组# 使用广播机制进行矩阵乘法
C = np.matmul(A, B)  # 广播矩阵乘法
print(C.shape)  # 输出 (100, 100, 100),C 的形状# 传统操作(不使用广播机制)
C_traditional = np.zeros((100, 100, 100), dtype=np.int64)  # 创建一个 100x100x100 的结果数组
for i in range(100):for j in range(100):for k in range(100):for l in range(3):C_traditional[i, j, k] += A[i, j, l] * B[k, l]  # 传统操作print(np.allclose(C, C_traditional))  # 输出 True,验证结果

2.6.7 附加:广播过程动态示意图

2.6.7.1 广播过程动态示意图

通过动态示意图,可以直观地展示广播机制的过程。

示例图
输入数组 A 输入数组 B 结果数组 C 广播机制 获取形状 (100, 100) 获取形状 (100, 100, 3) 计算需要扩展的维度数 在 A 的形状前面添加维度 (1, 100, 100) 检查 B 的形状是否需要扩展 扩展 A 的形状 (100, 100, 3) 创建结果数组 C (100, 100, 3) 执行广播操作 输入数组 A 输入数组 B 结果数组 C 广播机制
2.6.7.2 广播规则决策树

广播规则可以通过决策树的形式来展示,帮助理解广播机制的决策过程。

示例图
广播机制
检查形状
形状是否匹配
秩是否相同
是否需要扩展维度
扩展维度
是否需要重复
重复维度
广播成功
广播失败

2.6.8 广播机制在多维数组中的应用

2.6.8.1 多维数组广播的基本原理

在多维数组中,广播机制可以扩展数组的维度,以便在不同形状的数组之间进行操作。例如,一个四维数组与一个三维数组的广播操作。

示例代码
# 创建一个 10x10x10x1 的四维数组
A = np.random.randint(0, 256, size=(10, 10, 10, 1))  # 创建一个 10x10x10x1 的随机数组
print(A.shape)  # 输出 (10, 10, 10, 1)# 创建一个 10x10x10 的三维数组
B = np.random.randint(0, 256, size=(10, 10, 10))  # 创建一个 10x10x10 的随机数组
print(B.shape)  # 输出 (10, 10, 10)# 广播操作
C = A + B[:, :, :, np.newaxis]  # 广播操作
print(C.shape)  # 输出 (10, 10, 10, 1),C 的形状# 验证广播结果
for i in range(10):for j in range(10):for k in range(10):assert np.allclose(A[i, j, k, :], B[i, j, k])

2.6.9 广播机制的高级应用

2.6.9.1 广播机制在图像处理中的应用

在图像处理中,广播机制可以用于对图像的批量处理。例如,将一个批量的图像数据与一个单通道的滤波器进行卷积操作。

示例代码
# 创建一个 10x100x100x3 的图像数据
images = np.random.randint(0, 256, size=(10, 100, 100, 3))  # 创建一个 10x100x100x3 的随机图像数据
print(images.shape)  # 输出 (10, 100, 100, 3)# 创建一个 3x3 的单通道滤波器
filter_ = np.random.randn(3, 3)  # 创建一个 3x3 的随机滤波器
print(filter_.shape)  # 输出 (3, 3)# 扩展滤波器的维度
filter_expanded = filter_[:, :, np.newaxis, np.newaxis]  # 扩展滤波器的维度
print(filter_expanded.shape)  # 输出 (3, 3, 1, 1)# 执行卷积操作
conv_result = np.zeros((10, 98, 98, 3), dtype=np.int64)  # 创建卷积结果数组
for i in range(10):for j in range(98):for k in range(98):conv_result[i, j, k, :] = np.sum(images[i, j:j+3, k:k+3, :] * filter_expanded, axis=(0, 1))print(conv_result.shape)  # 输出 (10, 98, 98, 3),卷积结果的形状

2.6.10 广播机制在数据科学中的应用

2.6.10.1 广播机制在特征缩放中的应用

在数据科学中,广播机制可以用于特征缩放。例如,将一个批量的特征数据与一个标量进行缩放操作。

示例代码
# 创建一个 100x100 的特征数据
features = np.random.randn(100, 100)  # 创建一个 100x100 的随机特征数据
print(features.shape)  # 输出 (100, 100)# 创建一个标量
scale = 2.0  # 创建一个标量# 使用广播机制进行特征缩放
scaled_features = features * scale  # 广播操作
print(scaled_features.shape)  # 输出 (100, 100),缩放后的特征形状# 验证广播结果
for i in range(100):for j in range(100):assert np.allclose(scaled_features[i, j], features[i, j] * scale)

2.6.11 广播机制在机器学习中的应用

2.6.11.1 广播机制在损失函数中的应用

在机器学习中,广播机制可以用于计算损失函数。例如,计算均方误差(MSE)时,可以使用广播机制简化计算。

示例代码
# 创建一个 100x100 的预测数据
predictions = np.random.randn(100, 100)  # 创建一个 100x100 的随机预测数据
print(predictions.shape)  # 输出 (100, 100)# 创建一个 100x100 的真实数据
true_values = np.random.randn(100, 100)  # 创建一个 100x100 的随机真实数据
print(true_values.shape)  # 输出 (100, 100)# 计算均方误差(MSE)
mse = np.mean((predictions - true_values) ** 2)  # 广播操作
print(mse)  # 输出 MSE 值# 传统操作
mse_traditional = 0.0
for i in range(100):for j in range(100):mse_traditional += (predictions[i, j] - true_values[i, j]) ** 2
mse_traditional /= 100 * 100
print(mse_traditional)  # 输出传统计算的 MSE 值assert np.allclose(mse, mse_traditional)

2.6.12 广播机制在科学计算中的应用

2.6.12.1 广播机制在物理模拟中的应用

在科学计算中,广播机制可以用于物理模拟。例如,计算多个粒子之间的相互作用力。

示例代码
# 创建一个 100x3 的粒子位置数据
positions = np.random.randn(100, 3)  # 创建一个 100x3 的随机粒子位置数据
print(positions.shape)  # 输出 (100, 3)# 创建一个 100x3 的粒子质量数据
masses = np.random.randn(100, 1)  # 创建一个 100x1 的随机粒子质量数据
print(masses.shape)  # 输出 (100, 1)# 计算粒子之间的相互作用力
forces = np.zeros((100, 100, 3), dtype=np.float64)  # 创建一个 100x100x3 的结果数组
for i in range(100):for j in range(100):if i != j:r = positions[i] - positions[j]  # 广播操作r_norm = np.linalg.norm(r)  # 计算向量的模force = r * (masses[i] * masses[j] / r_norm ** 3)  # 计算力forces[i, j] = force  # 存储力print(forces.shape)  # 输出 (100, 100, 3),力的形状

2.6.13 广播机制的优化技巧

2.6.13.1 使用 np.broadcast_arrays 函数

np.broadcast_arrays 函数可以创建广播后的视图,而不需要实际复制数据,从而提高性能。

示例代码
# 创建一个 100x100 的二维数组
A = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组
print(A.shape)  # 输出 (100, 100)# 创建一个 100x100x3 的三维数组
B = np.random.randint(0, 256, size=(100, 100, 3))  # 创建一个 100x100x3 的随机数组
print(B.shape)  # 输出 (100, 100, 3)# 使用 np.broadcast_arrays 创建广播视图
A_broadcasted, B_broadcasted = np.broadcast_arrays(A, B)
print(A_broadcasted.shape)  # 输出 (100, 100, 3),广播后的 A 形状
print(B_broadcasted.shape)  # 输出 (100, 100, 3),广播后的 B 形状# 执行操作
C = A_broadcasted + B_broadcasted  # 广播操作
print(C.shape)  # 输出 (100, 100, 3),C 的形状

2.6.14 广播机制的常见问题与解决方法

2.6.14.1 常见问题
  1. 维度不匹配错误:当数组之间的维度不匹配且无法通过广播机制扩展时,会引发错误。
  2. 性能问题:在某些情况下,广播机制可能会导致性能损耗。
2.6.14.2 解决方法
  1. 检查数组形状:在进行广播操作前,确保数组的形状可以匹配。
  2. 优化内存布局:通过调整数组的内存布局,减少缓存未命中的概率。
示例代码
try:# 创建一个 100x100 的二维数组A = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组# 创建一个 100x100x2 的三维数组B = np.random.randint(0, 256, size=(100, 100, 2))  # 创建一个 100x100x2 的随机数组# 广播操作C = A + B  # 广播操作except ValueError as e:print(f"维度不匹配错误: {e}")# 优化内存布局
A = np.asfortranarray(A)  # 转换为 Fortran 顺序
B = np.ascontiguousarray(B)  # 转换为 C 顺序
C = A + B  # 广播操作
print(C.shape)  # 输出 (100, 100, 2),C 的形状

2.6.15 广播机制的实时应用案例

2.6.15.1 实时数据处理

在实时数据处理中,广播机制可以用于快速处理数据。例如,对实时流数据进行特征提取。

示例代码
# 创建一个实时数据流
def data_stream():while True:yield np.random.randn(100, 100)  # 生成一个 100x100 的随机数组# 创建一个特征提取器
def feature_extractor(data):# 创建一个 100x100x3 的特征矩阵features = np.random.randn(100, 100, 3)  # 创建一个 100x100x3 的随机特征矩阵print(features.shape)  # 输出 (100, 100, 3)# 广播操作extracted_features = data[:, :, np.newaxis] + features  # 广播操作print(extracted_features.shape)  # 输出 (100, 100, 3),提取的特征形状return extracted_features# 实时数据处理
stream = data_stream()
for i in range(10):data = next(stream)extracted_features = feature_extractor(data)print(extracted_features.shape)  # 输出 (100, 100, 3),每次处理的结果形状

2.6.16 广播机制的理论与实践结合

2.6.16.1 广播机制的理论基础

广播机制的理论基础在于线性代数中的向量和矩阵操作。通过数学模型和算法,可以更好地理解广播机制的工作原理。

在这里插入图片描述

2.6.16.2 实践例子

在实践例子中,广播机制可以用于图像增强。例如,将一个批量的图像数据与一个常量矩阵进行逐元素相加操作。

示例代码
# 创建一个 10x100x100x3 的图像数据
images = np.random.randint(0, 256, size=(10, 100, 100, 3))  # 创建一个 10x100x100x3 的随机图像数据
print(images.shape)  # 输出 (10, 100, 100, 3)# 创建一个 100x100 的常量矩阵
constant_matrix = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机常量矩阵
print(constant_matrix.shape)  # 输出 (100, 100)# 广播操作
enhanced_images = images + constant_matrix[:, :, np.newaxis, np.newaxis]  # 广播操作
print(enhanced_images.shape)  # 输出 (10, 100, 100, 3),增强后的图像形状# 验证广播结果
for i in range(10):for j in range(100):for k in range(100):assert np.allclose(enhanced_images[i, j, k, :], images[i, j, k, :] + constant_matrix[j, k])

2.6.17 广播机制的性能优化技巧

2.6.17.1 使用 @ 操作符

在 NumPy 中,@ 操作符可以用于矩阵乘法,比传统的 np.dot 更高效。

示例代码
import numpy as np
import time# 创建一个 100x100 的二维数组
A = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组
print(A.shape)  # 输出 (100, 100)# 创建一个 100x100 的二维数组
B = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组
print(B.shape)  # 输出 (100, 100)# 使用 @ 操作符进行矩阵乘法
start_time = time.time()
C = A @ B  # 广播操作
end_time = time.time()
print(C.shape)  # 输出 (100, 100),C 的形状
print(f"使用 @ 操作符的时间: {end_time - start_time} 秒")# 传统操作
start_time = time.time()
C_traditional = np.dot(A, B)  # 传统操作
end_time = time.time()
print(C_traditional.shape)  # 输出 (100, 100),C_traditional 的形状
print(f"使用 np.dot 的时间: {end_time - start_time} 秒")# 验证结果是否一致
assert np.allclose(C, C_traditional)

2.6.18 广播机制的高级技巧

2.6.18.1 使用 np.newaxis 动态扩展维度

np.newaxis 可以在数组的任意位置动态扩展维度,这对于某些复杂的广播操作非常有用。

示例代码
# 创建一个 100x100 的二维数组
A = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组
print(A.shape)  # 输出 (100, 100)# 创建一个 100x100 的二维数组
B = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组
print(B.shape)  # 输出 (100, 100)# 动态扩展维度
A_expanded = A[:, :, np.newaxis]  # 扩展 A 的维度到 (100, 100, 1)
B_expanded = B[:, :, np.newaxis]  # 扩展 B 的维度到 (100, 100, 1)# 广播操作
C = A_expanded + B_expanded  # 广播操作
print(C.shape)  # 输出 (100, 100, 2),C 的形状# 验证广播结果
for i in range(100):for j in range(100):assert np.allclose(C[i, j, 0], A[i, j])assert np.allclose(C[i, j, 1], B[i, j])

2.6.19 广播机制的注意事项

2.6.19.1 维度扩展的限制

广播机制有一些限制,如形状不匹配时无法进行广播。此外,扩展维度时需要注意数组的内存分配和效率问题。

示例代码
# 创建一个 100x100 的二维数组
A = np.random.randint(0, 256, size=(100, 100))  # 创建一个 100x100 的随机数组
print(A.shape)  # 输出 (100, 100)# 创建一个 100x100x2 的三维数组
B = np.random.randint(0, 256, size=(100, 100, 2))  # 创建一个 100x100x2 的随机数组
print(B.shape)  # 输出 (100, 100, 2)try:# 尝试广播操作C = A + B  # 广播操作
except ValueError as e:print(f"维度不匹配错误: {e}")# 解决方法:确保形状匹配
A_expanded = A[:, :, np.newaxis]  # 扩展 A 的维度到 (100, 100, 1)
C = A_expanded + B  # 广播操作
print(C.shape)  # 输出 (100, 100, 2),C 的形状

2.6.20 广播机制与其他计算工具的对比

2.6.20.1 与 TensorFlow 的对比

在 TensorFlow 中,广播机制类似但有一些差异。TensorFlow 提供了更高级的张量操作和优化,适合大规模的机器学习任务。

TensorFlow 示例代码
import tensorflow as tf# 创建一个 100x100 的二维数组
A = tf.random.uniform(shape=(100, 100), minval=0, maxval=256, dtype=tf.int32)
print(A.shape)  # 输出 (100, 100)# 创建一个 100x100x3 的三维数组
B = tf.random.uniform(shape=(100, 100, 3), minval=0, maxval=256, dtype=tf.int32)
print(B.shape)  # 输出 (100, 100, 3)# 广播操作
C = A[:, :, tf.newaxis] + B  # 广播操作
print(C.shape)  # 输出 (100, 100, 3),C 的形状# 验证广播结果
for i in range(100):for j in range(100):for k in range(3):assert tf.reduce_all(A[i, j] + B[i, j, k] == C[i, j, k])

2.6.21 广播机制的总结

2.6.21.1 总结

广播机制是 NumPy 中的一个强大工具,能够简化数组操作,提高代码的可读性和效率。通过合理使用广播机制,可以避免显式的循环和复制操作,使代码更加简洁和高效。然而,在使用广播机制时,需要注意维度扩展的限制和性能问题,以确保代码的正确性和效率。

2.6.22 广播机制的未来发展方向

2.6.22.1 未来方向
  1. 更高效的广播算法:随着硬件和软件技术的发展,广播机制的算法可以进一步优化,提高性能。
  2. 更多维度的支持:未来的广播机制可能会支持更高维度的数组操作,满足更复杂的应用需求。
  3. 与其他计算框架的集成:广播机制可以更好地与其他计算框架(如 TensorFlow 和 PyTorch)集成,提供更统一的编程接口。

2.6.23 实践练习

2.6.23.1 练习题
  1. 基本广播操作

    • 创建两个形状分别为 (100, 100) 和 (100, 100, 3) 的随机数组,并使用广播机制将它们相加。
    • 验证结果是否正确。
  2. 图像处理

    • 创建一个批量图像数据,形状为 (10, 100, 100, 3)。
    • 创建一个单通道滤波器,形状为 (3, 3)。
    • 使用广播机制对图像数据进行卷积操作,并验证结果是否正确。
  3. 特征缩放

    • 创建一个形状为 (100, 100) 的特征数据。
    • 创建一个标量值 2.0。
    • 使用广播机制对特征数据进行缩放操作,并验证结果是否正确。

2.6.24 参考资料

2.6.24.1 书籍
  • 《NumPy Beginner’s Guide》:提供 NumPy 的基础和高级使用方法,详细介绍了广播机制。
  • 《Python for Data Analysis》:通过实例讲解了 NumPy 和 Pandas 在数据科学中的应用。
2.6.24.2 在线文档
  • NumPy 官方文档:提供详细的广播机制说明和示例。

    • NumPy Broadcasting Documentation
  • TensorFlow 官方文档:介绍 TensorFlow 中的广播机制和张量操作。

    • TensorFlow Broadcasting Documentation

2.6.25 常见问题解答

2.6.25.1 什么是广播机制?

广播机制是 NumPy 中的一种数组操作方式,允许形状不同的数组进行逐元素操作。通过扩展数组的维度,使它们在操作中具有相同的形状。

2.6.25.2 广播机制有什么好处?
  • 简化代码:避免显式的循环和复制操作,使代码更加简洁。
  • 提高效率:通过内部优化,提高数组操作的性能。
  • 增强可读性:使代码更易于理解和维护。
2.6.25.3 广播机制有哪些限制?
  • 维度不匹配:当数组之间的维度不匹配且无法通过广播机制扩展时,会引发错误。
  • 性能问题:在某些情况下,广播机制可能会导致内存占用增加或性能下降。

2.6.26 附录

2.6.26.1 术语表
  • 广播(Broadcasting):NumPy 中的一种机制,允许形状不同的数组进行逐元素操作。
  • 维度(Dimension):数组的轴数,表示数组的维度。
  • 秩(Rank):数组的维度数,即轴的数量。
  • 形状(Shape):数组的维度大小,表示每个维度上的元素数量。
  • 向量(Vector):一维数组。
  • 矩阵(Matrix):二维数组。
  • 张量(Tensor):三维及以上维度的数组。

2.6.27 结语

通过本章节的学习,希望你已经掌握了 NumPy 中的广播机制及其在各种实际应用中的使用方法。广播机制是处理多维数组的强大工具,合理使用可以显著提高代码的效率和可读性。如这篇文章包含了详细的原理介绍、代码示例、源码注释以及案例等。希望这对您有帮助。如果有任何问题请随私信或评论告诉我。

相关文章:

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.6 广播机制核心算法:维度扩展的数学建模

2.6 广播机制核心算法&#xff1a;维度扩展的数学建模 目录/提纲 #mermaid-svg-IfELXmhcsdH1tW69 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-IfELXmhcsdH1tW69 .error-icon{fill:#552222;}#mermaid-svg-IfELXm…...

K8S极简教程(4小时快速学会)

1. K8S 概览 1.1 K8S 是什么 K8S官网文档&#xff1a;https://kubernetes.io/zh/docs/home/ 1.2 K8S核心特性 服务发现与负载均衡&#xff1a;无需修改你的应用程序即可使用陌生的服务发现机制。存储编排&#xff1a;自动挂载所选存储系统&#xff0c;包括本地存储。Secret和…...

系统URL整合系列视频二(界面原型)

视频 系统URL整合系列视频二&#xff08;界面原型&#xff09; 视频介绍 &#xff08;全国&#xff09;大型分布式系统Web资源URL整合需求界面原型讲解。当今社会各行各业对软件系统的web资源访问权限控制越来越严格&#xff0c;控制粒度也越来越细。安全级别提高的同时也增加…...

虚幻浏览器插件 UE与JS通信

温馨提示&#xff1a;本节内容需要结合插件Content下的2_Communication和Resources下的sample.html 一起阅读。 1. UE调用JS 1.1 JS脚本实现 该部分共两步: 导入jstote.js脚本实现响应函数并保存到 ue.interface 中 jsfunc 通过json对象传递参数&#xff0c;仅支持函数名小…...

OpenAI深夜反击:o3-mini免费上线,能否撼动DeepSeek的地位?

还在为寻找合适的 AI 模型而烦恼吗&#xff1f;chatTools 平台为您精选 o1、GPT4o、Claude、Gemini 等顶尖 AI 模型&#xff0c;满足您不同的 AI 应用需求。立即体验强大的 AI 能力&#xff01; 深夜反击&#xff0c;OpenAI祭出o3-mini 在DeepSeek异军突起&#xff0c;搅动AI行…...

Golang 应用的 Docker 部署方式介绍及使用详解

本文将介绍如何使用 Docker 部署一个基于 Go 语言的后台服务应用 godco&#xff0c;并介绍如何配置 MongoDB 数据库容器的连接&#xff0c;确保应用能够成功启动并连接到容器方式部署的mongoDB数据库。 前提条件 1.已安装 Docker/Podman 2.已安装 MongoDB 数据库容器&#xff…...

deep seek R1本地化部署及openAI API调用

先说几句题外话。 最近deep seek火遍全球&#xff0c;所以春节假期期间趁着官网优惠充值了deep seek的API&#xff0c;用openAI的接口方式尝试了下对deep seek的调用&#xff0c;并且做了个简单测试&#xff0c;测试内容确实非常简单&#xff1a;通过prompt提示词让大模型对用…...

力扣第435场周赛讲解

文章目录 题目总览题目详解3442.奇偶频次间的最大差值I3443.K次修改后的最大曼哈顿距离3444. 使数组包含目标值倍数的最少增量3445.奇偶频次间的最大差值 题目总览 奇偶频次间的最大差值I K次修改后的最大曼哈顿距离 使数组包含目标值倍数的最少增量 奇偶频次间的最大差值II …...

初入机器学习

写在前面 本专栏专门撰写深度学习相关的内容&#xff0c;防止自己遗忘&#xff0c;也为大家提供一些个人的思考 一切仅供参考 概念辨析 深度学习&#xff1a; 本质是建模&#xff0c;将训练得到的模型作为系统的一部分使用侧重于发现样本集中隐含的规律难点是认识并了解模型&…...

Signature

Signature 题目是&#xff1a; import ecdsaimport random​def ecdsa_test(dA,k):​sk ecdsa.SigningKey.from_secret_exponent(secexpdA,curveecdsa.SECP256k1)sig1 sk.sign(databHi., kk).hex()sig2 sk.sign(databhello., kk).hex()#不同的kr1 int(sig1[:64], 16)s1 i…...

93,【1】buuctf web [网鼎杯 2020 朱雀组]phpweb

进入靶场 页面一直在刷新 在 PHP 中&#xff0c;date() 函数是一个非常常用的处理日期和时间的函数&#xff0c;所以应该用到了 再看看警告的那句话 Warning: date(): It is not safe to rely on the systems timezone settings. You are *required* to use the date.timez…...

笔灵ai写作技术浅析(四):知识图谱

知识图谱(Knowledge Graph)是一种结构化的知识表示方式,通过将知识以图的形式进行组织,帮助AI系统更好地理解和利用信息。在笔灵AI写作中,知识图谱技术被广泛应用于结构化组织各种领域的知识,使AI能够根据写作主题快速获取相关的背景知识、概念关系等,从而为生成内容提供…...

Chromium132 编译指南 - Android 篇(四):配置 depot_tools

1. 引言 在前面的章节中&#xff0c;我们详细介绍了编译 Chromium 132 for Android 所需的系统和硬件要求&#xff0c;以及如何安装和配置基础开发环境和常用工具。完成这些步骤后&#xff0c;接下来需要配置 depot_tools&#xff0c;这是编译 Chromium 的关键工具集。depot_t…...

使用真实 Elasticsearch 进行高级集成测试

作者&#xff1a;来自 Elastic Piotr Przybyl 掌握高级 Elasticsearch 集成测试&#xff1a;更快、更智能、更优化。 在上一篇关于集成测试的文章中&#xff0c;我们介绍了如何通过改变数据初始化策略来缩短依赖于真实 Elasticsearch 的集成测试的执行时间。在本期中&#xff0…...

SQL进阶实战技巧:如何分析浏览到下单各步骤转化率及流失用户数?

目录 0 问题描述 1 数据准备 2 问题分析 3 问题拓展 3.1 跳出率计算...

机器学习--概览

一、机器学习基础概念 1. 定义 机器学习&#xff08;Machine Learning, ML&#xff09;&#xff1a;通过算法让计算机从数据中自动学习规律&#xff0c;并利用学习到的模型进行预测或决策&#xff0c;而无需显式编程。 2. 与编程的区别 传统编程机器学习输入&#xff1a;规…...

低代码系统-产品架构案例介绍、炎黄盈动-易鲸云(十二)

易鲸云作为炎黄盈动新推出的产品&#xff0c;在定位上为低零代码产品。 开发层 表单引擎 表单设计器&#xff0c;包括设计和渲染 流程引擎 流程设计&#xff0c;包括设计和渲染&#xff0c;需要说明的是&#xff1a;采用国际标准BPMN2.0&#xff0c;可以全球通用 视图引擎 视图…...

Electricity Market Optimization 探索系列(二)

​ 本文参考链接link 负荷持续时间曲线 (Load Duration Curve)&#xff0c;是根据实际的符合数据进行降序排序之后得到的一个曲线 这个曲线能够发现负荷在某个区间时&#xff0c;将会持续多长时间&#xff0c;有助于发电容量的规划 净负荷(net load) 是指预期负荷和预期可再生…...

OpenAI 实战进阶教程 - 第一节:OpenAI API 架构与基础调用

目标 掌握 OpenAI API 的基础调用方法。理解如何通过 API 进行内容生成。使用实际应用场景帮助零基础读者理解 API 的基本用法。 一、什么是 OpenAI API&#xff1f; OpenAI API 是一种工具&#xff0c;允许开发者通过编程方式与 OpenAI 的强大语言模型&#xff08;例如 gpt-…...

TensorFlow简单的线性回归任务

如何使用 TensorFlow 和 Keras 创建、训练并进行预测 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与预测 7. 保存与加载模型 8.完整代码 1. 数据准备与预处理 我们将使用一个简单的线性回归问题&#xff0c;其中输入特征 x 和标…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...