NumPy - 数组步长
NumPy 数组步长
在 NumPy 中,步长 是整数元组,表示遍历数组时在每个维度上要步长的字节数。它提供了访问数组元素而无需显式复制数据的能力。
步幅是根据数组的形状和数据类型计算的 -
- 对于数据类型为 4 字节的一维数组(例如 int32),步幅就是数据类型的大小。
- 对于多维数组,步幅的计算方法是将内维的大小乘以前一维的步幅。
在 NumPy 中访问步幅
您可以使用 strides 属性访问 NumPy 数组的步幅。此属性返回一个元组,其中每个值表示访问每个维度上的下一个元素时需要在内存中移动的字节数。
示例
在以下示例中,我们使用 NumPy 的"stride"属性计算数组的步长 -
import numpy as np # 创建二维数组 array = np.array([[1, 2, 3], [4, 5, 6]]) # 访问步长 print("数组步长:", array.strides)
步长 (24, 8) 表示从一行移动到下一行需要跳过 24 个字节,从一列移动到下一列需要跳过 8 个字节 -
数组步长: (24, 8)
NumPy 步幅的工作原理
步幅是根据数组的形状和数据类型计算的。对于给定维度,步幅是元素大小(以字节为单位)与后续维度元素数量的乘积。
对于形状为 (m, n) 且数据类型为 dtype 的二维数组 -
- 第一维的步幅:stride[0] = n * size_of(dtype)
- 第二维的步幅:stride[1] = size_of(dtype)
示例:基本步幅
在下面的示例中,我们访问基本一维 NumPy 数组的步幅 -
import numpy as np # 创建一维数组 array_1d = np.array([1, 2, 3, 4, 5]) # 访问步长 print("一维数组步长:", array_1d.strides)
步长 (8,) 表示每个元素在内存中相距 8 个字节,这对于整数数组来说是典型的 -
一维数组步长: (8,)
示例:更改步长
转置数组会更改步长,反映新的内存布局,如下例所示 -
import numpy as np # 创建二维数组 array_2d = np.array([[1, 2, 3], [4, 5, 6]]) # 转置数组 array_2d_T = array_2d.T # 访问步长 print("原始数组步长:", array_2d.strides) print("转置数组步长:", array_2d_T.strides)
步长 (8,) 表示每个元素在内存中相距 8 个字节,这对于整数数组来说是典型的 -
原始数组步长:(24, 8) 转置数组步长:(8, 24)
示例:使用步长进行内存优化
使用步长可以通过允许高效的访问模式来帮助优化内存使用 -
import numpy as np # 创建一个大数组 large_array = np.zeros((1000, 1000)) # 访问每 10 行 strided_array = large_array[::10, :] print("Strided 数组形状:", strided_array.shape) print("Strided 数组步长:", strided_array.strides)
步长表示我们跳过了 80,000 个字节(10 行)来访问下一行,从而优化了内存访问 -
Strided 数组形状:(100, 1000) Strided 数组步长:(80000, 8)
多维数据中的步长数组
多维数组中的步长工作原理类似,每个步长值表示相应维度的步长(以字节为单位)。
对于多维数组,每个维度的步长是元素大小与后续维度大小累积乘积的乘积。
这意味着最后一个维度的步长就是数据类型的大小,倒数第二个维度的步长是最后一个维度的大小乘以数据类型的大小,依此类推。
示例
在下面的示例中,我们计算三维数组的步长 -
import numpy as np # 创建三维数组 array_3d = np.zeros((2, 3, 4)) #访问步幅 print("3D 数组步幅:", array_3d.strides)
获取的步幅显示了每个维度的字节步长 -
3D 数组步幅:(96, 32, 8)
切片操作的步幅
在 NumPy 数组中执行切片操作时,步幅非常有用。切片 NumPy 数组时,通常会创建一个视图,而不是数组的副本。此视图共享相同的底层数据,但可能具有不同的形状或内存布局。
步幅决定了沿每个维度从一个元素移动到下一个元素时,在内存中需要移动多少字节。通过调整步长,您可以高效地访问特定模式的数据。
NumPy 中的切片操作允许您提取数组的子集,范围从单个元素到特定部分,而无需复制底层数据。
示例
在此示例中,我们创建一个大型二维数组,并使用步长切片操作访问每 10 行,而无需复制数据 -
import numpy as np # 创建一个大型二维数组 large_array = np.arange(10000).reshape((100, 100)) # 访问每 10 行 strided_array = large_array[::10, :] print("原始数组形状:", large_array.shape) print("Strided 数组形状:", strided_array.shape) print("Strided 数组步长:", strided_array.strides)
以下是获得的输出 -
原始数组形状:(100, 100) Strided 数组形状:(10, 100) Strided 数组步长:(4000, 40)