numpy中as_strided函数适用场景及图像排布实现疑问
关于numpy as_strided函数的两个问题
背景与示例代码
我正在练习使用numpy中的as_strided函数,先编写了一个示例:生成5个3×3的图像,每个图像分别填充1到5的数值,得到形状为(5,3,3)的3D数组。通过as_strided函数将其转换为形状为(5,9)的2D数组(每个3×3图像转为一行),代码及输出如下:
import numpy as np from numpy.lib.stride_tricks import as_strided array_3d = np.empty((5, 3, 3)) for i in range(5): array_3d[i] = np.full((3, 3), i+1) print(array_3d.itemsize) array_2d = as_strided(array_3d, shape=(5, 9), strides=(8*9, 8)) print(array_2d)
输出结果:
8 [[1. 1. 1. 1. 1. 1. 1. 1. 1.] [2. 2. 2. 2. 2. 2. 2. 2. 2.] [3. 3. 3. 3. 3. 3. 3. 3. 3.] [4. 4. 4. 4. 4. 4. 4. 4. 4.] [5. 5. 5. 5. 5. 5. 5. 5. 5.]]
需求描述
现在尝试更复杂的需求:将这些3×3图像横向并排,得到如下形状为(3,15)的数组:
[[1. 1. 1. 2. 2. 2. 3. 3. 3. 4. 4. 4. 5. 5. 5.] [1. 1. 1. 2. 2. 2. 3. 3. 3. 4. 4. 4. 5. 5. 5.] [1. 1. 1. 2. 2. 2. 3. 3. 3. 4. 4. 4. 5. 5. 5.]]
但无法仅通过as_strided函数实现该需求,因此提出两个问题:该需求是否仅用as_strided无法实现?除滑动窗口操作外,如何判断as_strided函数的适用场景?
问题解答
1. 该需求能否仅用as_strided实现?
答案是不能。原因在于as_strided要求目标数组的每个维度必须使用固定步长遍历原数组的内存,而这个需求的内存访问模式不符合这个规则:
- 原数组
array_3d的内存布局是连续的,每个3×3块(对应一个图像)的元素在内存中连续存储,即array_3d[0,0,0]之后依次是array_3d[0,0,1]、array_3d[0,0,2]、array_3d[0,1,0]...直到array_3d[0,2,2],才会到array_3d[1,0,0]。 - 目标数组的每行需要先取
array_3d[0,0,:](连续3个元素),接着跳转到array_3d[1,0,:],再连续取3个元素,之后再跳转,以此类推。这种模式下,每行内的步长会交替出现小步(8字节,连续元素)和大步(72字节,跳过整个3×3块),步长不固定,无法通过as_strided的固定步长参数实现。
若要实现该需求,需先调整原数组的内存布局(比如先转置得到(3,5,3),再reshape为(3,15)),但这已经不是单纯使用as_strided了。
2. 如何判断as_strided的适用场景(除滑动窗口外)?
可以通过以下核心原则判断:
- 固定步长规则:目标数组的所有元素必须能通过原数组内存的固定维度步长访问到,每个维度的步长值全程恒定,不能出现交替变化的步长。比如将
(5,3,3)转为(5,9)时,行维度步长是9×8字节(跳过整个3×3块),列维度步长是8字节(连续元素),两者都是固定值,符合要求。 - 视图而非重组:
as_strided的本质是创建原数组的内存视图,不复制数据。如果目标结构需要对原数组元素进行“重组式”排列(比如跨块拼接同一行元素),且这种排列无法通过固定步长的内存采样实现,就不适合用as_strided。 - 规律性访问:元素的访问逻辑必须具有全局一致性,比如:
- 合并/flatten连续的维度(如把高维数组的后几个维度展平);
- 按固定间隔采样元素(比如每隔N个元素取一个);
- 生成固定大小的滑动窗口(窗口内连续,窗口间步长固定)。
内容的提问来源于stack exchange,提问作者Jeff Boker
相关产品推荐
相关产品推荐

