赞
踩
numpy 的基本数据类型是ndarray(数组),ndarray在内存中的是一维连续存储,支持索引。换句话说,数组映射一个连续的内存块,可以使用索引值进行数据访问。索引依次由形状和数据类型定义。
- # 创建一个0-9的数组,改为3行3列的二维数组,单个元素的数据类型为np.int16(2个字节)
- z = np.arange(9).reshape(3,3).astype(np.int16)
-
- print(z.itemsize) # 单个元素的字节数
- 2
-
- print(z.shape) # 数组的形状
- (3, 3)
-
- print(Z.ndim) # 数组的维数
- 2
可以算出数组的stides步长,步长定义了遍历数组时每个维度中要跨步的字节数。
- strides = z.shape[1]*z.itemsize, z.itemsize
- print(strides)
- (6, 2)
-
- print(z.strides)
- # 第一个维度,也就是行方向上每行要跨出6(3*2)个字节
- # 第二个维度,也就是列方向上每列要跨出2个字节
- (6, 2)
数组元素布局
数组扁平化后元素布局
数组内存布局
当对数组使用索引取值时,返回的是原始数组的视图,比如
v = z[::2,::2] #两个维度上,每隔1个元素取值
数组元素布局
数组扁平化后元素布局
数组内存布局
首先要区分索引和花式索引,前者返回的是原始数组的视图,后者返回的是原始数据索引后的副本。修改前者的值会影响原始数组。
- z = np.zeros(9)
- z_view = z[:3]
- z_view[...] = 1
- print(z)
- out:[ 1. 1. 1. 0. 0. 0. 0. 0. 0.]
-
- z = np.zeros(9)
- z_copy = z[[0,1,2]] # 花式索引
- z_copy[...] = 1
- print(z)
- out:[ 0. 0. 0. 0. 0. 0. 0. 0. 0.]
如果不确定索引返回的是原始数组的视图还是副本,可以通过结果的base属性确认,如果base的值是None,则返回的结果是副本。
注意某些numpy函数返回的是视图,比如ravel,而flatten返回的是副本,虽然两者都得到扁平后的数据。
- X = np.ones(10, dtype=np.int)
- Y = np.ones(10, dtype=np.int)
- A = 2*X + 2*Y
运行上边的代码,除了显式的产生了X,Y和A三个数组外,还隐式的生成了两个数组2*X和2*Y。当数组非常大的时候可能会产生性能问题。解决问题的办法是显示调用numpy函数中的out参数, 明确指定输出结果到已经声明的变量。
- X = np.ones(10, dtype=np.int)
- Y = np.ones(10, dtype=np.int)
- np.multiply(X, 2, out=X)
- np.multiply(Y, 2, out=Y)
- np.add(X, Y, out=X)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。