新闻中心

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

2025-11-06
浏览次数:
返回列表

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 迭代中检测空数组元素的有效方法 

搜索