新闻中心
NumPy 2D数组高效块级修改:基于视图与查找表的策略

本教程旨在介绍如何利用numpy的`np.lib.stride_tricks.as_strided`功能,结合查找表机制,高效地对2d数组进行2x2块级别的修改。通过创建数组视图而非复制数据,并利用高级索引进行矢量化操作,此方法显著优于传统的python循环,极大提升了处理大型数据集的性能。
引言:Python循环的性能瓶颈
在处理大型NumPy数组时,如果需要对数组中的局部小块(例如2x2的子矩阵)进行模式识别和替换操作,传统的Python循环(如使用itertools.product遍历坐标)会因为解释器开销和逐元素操作而效率低下。NumPy的核心优势在于其矢量化操作,能够将循环操作推送到C语言层面执行,从而获得显著的性能提升。本教程的目标是展示如何采用NumPy原生的、矢量化的方式来高效地实现2D数组的2x2块级修改。
核心策略:利用NumPy视图与步幅技巧
实现高效块级操作的关键在于np.lib.stride_tricks.as_strided。这个函数允许我们创建一个现有NumPy数组的“视图”,而无需复制底层数据。通过巧妙地定义视图的shape(形状)和strides(步幅),我们可以将一个2D数组解释为一个由多个2x2块组成的更高维数组。对这个视图的修改会直接反映在原始数组上,从而避免了昂贵的数据复制操作。
理解 shape 和 strides 参数
shape: 新视图的形状。对于一个 (ny, nx) 的原始2D数组 A,如果我们要以 (2, 2) 的块进行操作,那么新的视图的形状将是 (ny//2, nx//2, 2, 2)。这表示视图包含 ny//2 行和 nx//2 列,每个“元素”本身又是一个 (2, 2) 的子数组。
-
strides: 定义了在内存中沿着某个维度移动一个单位所需的字节数。
- 对于原始数组 A,其步幅为 A.strides = (row_stride, col_stride),其中 row_stride 是跳到下一行所需的字节数,col_stride 是跳到下一列所需的字节数。
- 为了在视图中从一个2x2块的起始位置跳到下一个2x2块的起始位置(即视图的第一和第二个维度),我们需要在原始数组中跳过两行或两列。因此,视图的第一个维度(块行)步幅是 A.strides[0] * 2,第二个维度(块列)步幅是 A.strides[1] * 2。
- 为了在视图内部的2x2块中移动(即视图的第三和第四个维度),我们需要按照原始数组的行和列步幅来移动。因此,视图的第三个维度(块内行)步幅是 A.strides[0],第四个维度(块内列)步幅是 A.strides[1]。
- 综合起来,视图的步幅将是 (A.strides[0]*2, A.strides[1]*2, A.strides[0], A.strides[1])。
示例:创建2x2块视图
import numpy as np
# 示例数据:一个10x10的二进制数组
A = np.random.randint(0, 2, (10, 10))
print("原始数组 A:")
print(A)
# 计算视图的形状和步幅
ny, nx = A.shape
block_rows = ny // 2
block_cols = nx // 2
# 创建2x2块的视图
Av = np.lib.stride_tricks.as_strided(A,
shape=(block_rows, block_cols, 2, 2),
strides=(A.strides[0] * 2, A.strides[1] * 2,
A.strides[0], A.strides[1]))
print("\n通过as_strided创建的2x2块视图 Av 的形状:", Av.shape)
print("Av[0,0] (原始数组A的第一个2x2块):\n", Av[0,0])
# 验证视图是否指向原始数据 (修改视图会影响原始数组)
# Av[0,0,0,0] = 99 # 修改视图的第一个元素
# print("\n修改Av[0,0,0,0]后,原始数组A的左上角:\n", A[:2,:2]) # 原始数组A也会随之改变方法一:基于多维查找表的块替换
当每个2x2块的替换规则依赖于其内部的四个元素时,我们可以构建一个多维查找表(Lookup Table, LUT)。对于由布尔值(0或1)组成的2x2块,共有 2^4 = 16 种可能的状态。查找表将以前四个元素的值作为索引,存储对应的2x2替换块。
刺鸟创客
一款专业高效稳定的AI内容创作平台
110
查看详情
构建与应用查找表
查找表的形状将是 (2, 2, 2, 2, 2, 2),其中前四个 2 对应输入2x2块的四个元素 (0,0), (0,1), (1,0), (1,1) 的值,后两个 2 对应替换后的2x2块的形状。
# 示例查找表 (lut[val00, val01, val10, val11] = replacement_block)
# lut的形状为 (2,2,2,2, 2,2)
# 前四个2代表2x2块的四个元素 (0,0), (0,1), (1,0), (1,1) 的值
# 后两个2代表替换后的2x2块的形状
lut = np.zeros((2, 2, 2, 2, 2, 2), dtype=A.dtype)
# 填充一些转换规则。例如:
# 1. 原始块 [[0,0],[0,0]] 替换为 [[1,1],[1,1]]
lut[0, 0, 0, 0] = [[1, 1], [1, 1]]
# 2. 原始块 [[0,0],[0,1]] 替换为 [[1,1],[1,0]]
lut[0, 0, 0, 1] = [[1, 1], [1, 0]]
# 3. 原始块 [[0,1],[0,0]] 替换为 [[1,1],[0,1]]
lut[0, 1, 0, 0] = [[1, 1], [0, 1]]
# 4. 原始块 [[1,1],[0,0]] 替换为 [[1,1],[1,1]]
lut[1, 1, 0, 0] = [[1, 1], [1, 1]]
# ... 可以根据需要填充所有16种情况
# 应用查找表进行块替换
# 使用高级索引,将Av中的每个2x2块的四个元素作为lut的索引
Av[:] = lut[Av[..., 0, 0], Av[..., 0, 1], Av[..., 1, 0], Av[..., 1, 1]]
print("\n方法一:使用多维查找表后的数组 A:")
print(A)方法二:基于一维查找表与索引转换的块替换
为了简化查找表的索引,我们可以将每个2x2块的四个布尔值转换为一个单一的整数索引(0-15)。这可以通过为每个位置分配一个权重并求和来实现。这种方法可以使查找表更紧凑,并可能简化索引逻辑。
索引转换与一维查找表
我们可以定义一个权重矩阵,例如:
[[8, 4], [2, 1]]
对于一个2x2块 [[v00, v01], [v10, v11]],其对应的单一索引将是 v00*8 + v01*4 + v10*2 + v11*1。这个索引的范围是0到15。
# 重新初始化数组A进行演示
A = np.random.randint(0, 2, (10, 10))
ny, nx = A.shape
block_rows = ny // 2
block_cols = nx // 2
Av = np.lib.stride_tricks.as_strided(A,
shape=(block_rows, block_cols, 2, 2),
strides=(A.strides[0]
* 2, A.strides[1] * 2,
A.strides[0], A.strides[1]))
print("\n重新初始化后的原始数组 A:")
print(A)
# 示例一维查找表 (lut2[index] = replacement_block)
lut2 = np.zeros((16, 2, 2), dtype=A.dtype)
# 填充一些转换规则。例如:
# 索引0 (对应原始块 [[0,0],[0,0]]) 替换为 [[1,1],[1,1]]
lut2[0] = [[1, 1], [1, 1]]
# 索引1 (对应原始块 [[0,0],[0,1]]) 替换为 [[1,1以上就是NumPy 2D数组高效块级修改:基于视图与查找表的策略的详细内容,更多请关注其它相关文章!
# 如何使用
# 潍城网站优化推广费用
# 瓷砖网站优化方法哪家好
# 网站建设比较专业
# seo的空间构型
# kol营销推广怎么选
# 杭州seo软件专注乐云seo品牌
# 铜仁律师网站推广公司
# 南京建设部网站
# 焦大seo复制
# 寮步培训机构网站建设
# 矢量化
# python
# 于其
# 第二个
# 跳到
# 所需
# 第一个
# 将是
# 我们可以
# 多维
# 性能瓶颈
# 字节
# c语言
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
C++如何实现一个智能指针_手动实现C++ shared_ptr的引用计数功能
印象笔记怎样用批量导出备知识库_印象笔记用批量导出备知识库【备份方法】
qq浏览器打开空白页怎么办 qq浏览器启动后显示白屏的解决教程
Pandas DataFrame 多条件优先级排序与排名
zookeeper 都有哪些功能?
React Router v6 教程:构建认证保护的私有路由与重定向策略
格力空气能E5故障代码是什么情况_格力空气能E5代码解析与应对措施
优化LangChain文档加载与ChromaDB集成:解决多文档处理与分块问题
不会效仿卡普空!《铁拳》制作人澄清:不采取赛事付费|直播|
学习通网页版官方登录 超星学习通电脑端入口指南
b站怎么取消点赞_b站点赞取消操作方法
Composer如何解决json扩展缺失的错误
Win11怎么用U盘重装系统 Win11制作启动盘并重装系统完整教程【详解】
优化Log4j2控制台输出性能:解决异步日志瓶颈
极兔快递快件信息查询系统 极兔快递官网运单号追踪
Win11如何开启讲述人功能 Win11屏幕阅读器(讲述人)开启与关闭【教程】
顺丰快递查单号物流信息 顺丰快递小程序查询入口
html两个JS只运行一个怎么办_让双JS在html中都运行方法【技巧】
谷歌浏览器一键优化方案_谷歌浏览器直达主页极速不卡版
Golang如何使用buffered channel提高性能_Golang buffered channel优化技巧
Python中如何避免重复条件判断:利用数据结构实现动态逻辑
小米14应用无法联网原因分析_小米14网络权限修复
一加Ace 6T实拍样张首次公布!李杰:主摄实力完全看齐4K档性能旗舰
12306选座怎么选到特殊座位_12306特殊座位选择注意事项
腾讯QQ邮箱官方网站_QQ邮箱网页版在线登录
html怎么运行外部js文件中的函数_运html外js文件函数法【技巧】
QQ邮箱在线登录平台 QQ邮箱个人邮箱网页版入口
LINUX的I/O重定向是什么_深入理解LINUX中 >、>> 与 < 的区别
蛙漫安全无毒 官方认证的绿色入口
汽水音乐在线解析 汽水音乐在线解析入口
Pygame教程:解决用户输入与游戏状态更新不同步问题
Go语言HTML解析:利用Goquery精准获取指定元素内容
探索高级语言到原生C/C++的转译:挑战与内存管理策略
蛙漫2日版入口 WAMAN2(日版)无删减漫画官网链接
荒野行动PC版怎么注册_荒野行动PC版账号注册详细流程图文教程
Go语言JSON解析深度指南:动态访问与结构体映射实践
Node.js CSV 数据处理:基于字段值条件过滤整条记录的策略
新手怎么开始学化妆 零基础化妆入门教程
EMS快递官网app_中国邮政速递物流手机客户端
微博网页版主页入口 微博官方网站免登录访问
微信网页版官方入口直达 微信网页版网页版登录使用方法
win11专注助手在哪 Win11免打扰模式设置与自动化规则【指南】
学习通在线学习平台 学习通网页版直接进入课程中心
一加手机电池耗电快怎么办_一加手机电池耗电快的解决方法
2026年CSGO开箱网站推荐 CSGO开箱平台精选
MongoDB Aggregation:在嵌套对象数组中精确匹配ObjectId
Golang如何实现简单的Web表单_Golang表单提交与验证处理方法
mysql如何设置表访问权限_mysql表访问权限配置
微信聊天记录怎么加密_微信聊天记录加密方法
J*aScript map 迭代中检测空数组元素的有效方法


2025-11-06
浏览次数:次
返回列表
* 2, A.strides[1] * 2,
A.strides[0], A.strides[1]))
print("\n重新初始化后的原始数组 A:")
print(A)
# 示例一维查找表 (lut2[index] = replacement_block)
lut2 = np.zeros((16, 2, 2), dtype=A.dtype)
# 填充一些转换规则。例如:
# 索引0 (对应原始块 [[0,0],[0,0]]) 替换为 [[1,1],[1,1]]
lut2[0] = [[1, 1], [1, 1]]
# 索引1 (对应原始块 [[0,0],[0,1]]) 替换为 [[1,1