1. ndarray 对象的内存结构
ndarray
对象在内存中的结构如下:ndarray.dtype
:存储了数组保存的元素的类型。float32
ndarray.ndim
:它是一个整数,保存了数组的维度,即多少个轴ndarray.shape
:它是一个整数的元组,每个元素一一对应地保存了数组某个维度的大小(即某个轴的长度)。ndarray.strides
:它是一个整数的元组,每个元素保存着每个轴上相邻两个元素的地址差。即当某个轴的下标增加1 时,数据存储区中的指针增加的字节数ndarray.data
:它指向数组的数据的存储区
可以看到:该数组中元素类型为
float32
;该数组有2 个轴。每个轴的长度都是 3 个元素。第 0 轴增加1时,下标增加 12字节(也就是 3个元素,即一行的距离); 第 1 轴增加 1时,下标增加 4字节(也就是一个元素的距离)。元素在数据存储区中的排列格式有两种:
C
语言格式和Fortran
语言格式。C
语言中,多维数组的第 0 轴是最外层的。即 0 轴的下标增加 1时,元素的地址增加的字节数最多Fortran
语言中,多维数组的第 0 轴是最内层的。即 0 轴的下标增加 1时,元素的地址增加的字节数最少
numpy
中默认是以C
语言格式存储数据。如果希望改为Fortran
格式,则只需要在创建数组时,设置order
参数为"F"
数组的
flags
属性描述了数据存储区域的一些属性。你可以直接查看flags
属性,也可以单独获取其中某个标志值。C_CONTIGUOUS
:数据存储区域是否是C
语言格式的连续区域F_CONTIGUOUS
:数据存储区域是否是F
语言格式的连续区域OWNDATA
:数组是否拥有此数据存储区域。当一个数组是其他数组的视图时,它并不拥有数据存储区域,通过视图数组的base
属性可以获取保存数据存储区域的那个原始数组。
数组的转置可以通过其
T
属性获取。转置数组可以简单的将其数据存储区域看作是Fortran
语言格式的连续区域,并且它不拥有数据存储区域。修改数组的内容时,会直接修改数据存储区域。所有使用该数据存储区域的数组都将被同时修改!
1.1 dtype
numpy
有自己的浮点数类型:float16/float32/float64/float128
等等。- 在需要指定
dtype
参数时,你可以使用numpy.float16
,也可以传递一个表示数值类型的字符串。numpy
中的每个数值类型都有几种字符串表示。字符串和类型之间的对应关系都存储在numpy.typeDict
字典中。 dtype
是一种对象,它不同于数值类型。只有dtype.type
才能获取对应的数值类型- 你可以通过
np
的数值类型np.float32
来创建数值对象。但要注意:numpy
的数值对象的运算速度比python
内置类型的运算速度要慢很多。所以应当尽量避免使用numpy
的数值对象
- 在需要指定
- 使用
ndarray.astype()
方法可以对数组元素类型进行转换。
1.2 shape
你可以使用
ndarray.reshape()
方法调整数组的维度。- 你可以在某个维度设置其长度为 -1,此时该维度的长度会被自动计算
你可以直接修改
ndarry
的shape
属性,此时直接修改原始数组。- 你可以在某个维度设置其长度为 -1,此时该维度的长度会被自动计算
1.3 view
- 我们可以通过
ndarray.view()
方法,从同一块数据区创建不同的dtype
数组。即使用不同的数值类型查看同一段内存中的二进制数据。它们使用的是同一块内存。 - 如果我们直接修改原始数组的
dtype
,则同样达到这样的效果,此时直接修改原始数组。
1.4 strides
- 我们可以直接修改
ndarray
对象的strides
属性。此时修改的是原始数组。 - 你可以使用
np.lib.stride_tricks.as_stride()
函数创建一个不同strides
的视图。 注意:使用as_stride
时并不会执行内存越界检查,因此shape
和stride
设置不当可能会发生意想不到的错误。
1.5 拷贝和视图
当处理
ndarray
时,它的数据存储区有时被拷贝,但有时并不被拷贝。有三种情况。完全不拷贝:简单的赋值操作并不拷贝
ndarray
的任何数据,这种情况下是新的变量引用ndarray
对象(类似于列表的简单赋值)视图和浅拷贝:不同的
ndarray
可能共享相同的数据存储区。如ndarray.view()
方法创建一个新的ndarray
但是与旧ndarray
共享相同的数据存储区。新创建的那个数组称作视图数组。- 对于视图数组,
ndarray.base
返回的是拥有数据存储区的那个底层ndarray
。而非视图数组的ndarray.base
返回None
ndarray.flags.owndata
返回数组是否拥有基础数据- 对于数组的分片操作返回的是一个
ndarray
的视图。对数组的索引返回的不是视图,而是含有基础数据。
- 对于视图数组,
- 深拷贝:
ndarray.copy()
操作会返回一个完全的拷贝,不仅拷贝ndarray
也拷贝数据存储区。