在使用
NumPy
的数组时,经常会遇到改变数组形状,对数组进行重塑的需求,因此在此进行学习整理,有不准确或者错误的地方还请指正。
1. reshape
ndarray.reshape(new_shape, order='C')
numpy.reshape(a, new_shape, order='C')
参数
- a: 要重新整形的数组。
- new_shape: int或int的元组
- order: ‘C’、‘F’、‘A’,可选
1.1 ndarray.reshape(new_shape) 与 np.reshape(a, new_shape)
的区别
NumPy
中有大量的这种现象,有些地方会将a.xxx()
称为方法调用(看作面向对象),而将numpy.xxx(a)
称为自由函数。有时候这两种调用方式的效果是完全一样的,而有时候又会有一些差别,就reshape
而言两者有一点的不同:
a.reshape((2, 3))
可以直接写作a.reshape(2, 3)
,而np.reshape(a, (2, 3))
写作np.reshape(a, 2, 3)
会报错这其中最直接原因可能是(个人看法)
a.reshape()
参数中在不考虑order
之外只有一个new_shape
,无论是(2, 3)
还是2, 3
都可以明确其含义,而反观np.reshape()
既有a
参数,又有new_shape
参数,不太容易区分
1.2 reshape
返回的是数组的一个视图(可能)
如果对
reshape
返回的结果进行修改,原数组也会在相应位置进行修改
其实官方文档上说的是:如果可能的话,会返回一个视图,否则将是一个数组的副本,所以说就是不保证一定是一个视图
其实这话说了一点用也没有,也没有说到底啥时候返回一个视图,啥时候返回一个副本,不过我使用的时候还没有遇到不是副本的情况,可能没有遇到特殊情况吧
1.3 关于参数new_shape
new_shape
的取值是必须的,不能省略,有以下三种情况:(假设数组元素总数为N
)
- ,且
也就是说,各维度的长度乘积要把数组中的值一个不漏地安排完
也就说,可以允许一个维度上的取值为-1
,至于该维度上的长度究竟是多少,由numpy
自己推算,原则还是那一条:所有数据必须一个不能少
当参数值为一个int
类型的整数是,必须是N
,即该数组的元素总数,不能是其他数值,此时表示将该数组重塑为一维数组
1.4 关于参数order
order
是一个可选参数,可选值为:'C'、'F'、'A'
,默认为:'C'
我对取值为'A'
的情况还没有完全理解,因此只讨论取值为 'C'
和'F'
的情况
首先以二维数组为例:
a = np.array([[1, 2, 3],
[4, 5, 6]])
a.reshape(6)
根据 1.3
中对于参数newshape
的解释,可以确定上述代码最终的结果是将a
拉成一个一维数组,那么最终的结果是还是呢?绝大多数人的思维惯性会认为答案是前者,可是答案有没有可能是后者呢?是有可能的!order
参数就是来解决这个问题的。
order
缺省情况下,取值为C
,即首先按照 行 来读取元素,进而实现重塑;而当取值为F
时,即首先按照 列 来读取元素,进而实现重塑,就得到了上文中提到的第二种结果
推广到高维数组 ,order
参数取值为C
表示首先按照 来读取元素,其次是 ,依次到最后一个是 ;取值为 F
时刚好相反,首先按照 来读取元素,其次是 ,依次到最后一个是 。
numpy
中的很多函数都有这个参数,大多数都是这个含义
其实我们一般都习惯缺省值,思维习惯吧。
2. resize
2.1 np.rersize
ndarray.resize(a, new_shape)
参数
a
:要调整大小的数组。new_shape
:int
或int
的元组,要生成的数组的形状注意:如果新数组元素数目多于原始数组元素数目(
a
),多余部分将重复填充a
-
np.resize
函数几乎可以覆盖reshape
函数的功能,但是new_shape
中任一维度的取值均不能为-1
; - 当目标数组元素多余原始数组元素个数时,使用原始数组中的元素逐个填充,且是按照
C
顺序填充; -
np.resize
返回的结果数组不是原始数组的视图
2.2 ndarray.resize
ndarray.resize(new_shape, refcheck=True)
参数
new_shape
:int
或int
的元组,要生成的数组的形状refcheck
:可选的布尔值, 如果为false
,则不检查引用计数。默认值为true
注意:此方法就地更改数组的形状和大小;如果新数组元素数目多于原始数组元素数目(a),多余部分将用零填充,而不是重复复制
a
a.resize
方法就地改变 数组a
,没有返回值refcheck
参数默认缺省为true
,此时一般会报错,这个错误也是搞的一头雾水;但是当设置参数refcheck
为false
时,就会得到想要得到的数组,并且以0
填充多余的位置
2.3 总结
说实话,知道这次整理数组重塑的相关方法时候才发现原来numpy
中还有一个这样的函数(之前用opencv
中的resize
函数比较多)。并且该函数改变了数组的内容,并不是一般意义上的数组的重塑,不过或许其能够自动补充元素的功能会在之后有机会用到吧。
3. transpose
numpy.transpose(a, axes=None)
参数
a
:输入数组。axes
:元组或整数列表,可选
ndarray.transpose(*axes)
参数
axes
:元组或整数列表,可选
3.1 数组的转置
其实,numpy
中的这个transpose
函数对应的是数学概念中的数组的转置,转置的概念在二维层面很好理解,就是把行列调换位置呗,变为即可。但是,当数组超过二维时候,数组的这个转置概念就会变得比较抽象,理解起来也比较困难,所以此处就是就功能而言,不再涉及具体的数学概念,高维情况下比较多的是三维(opencv)和四维(深度学习中的tensor)等。
a.T
可以很简单的实现数组的转置
可以看到数组b
由原来的4*6
转置为6*4
- 对高维数组进行
.T
操作,会将所有的轴顺序倒序排列
数组d
由原来的2 * 3 * 4
变为4 * 3 * 2
-
.T
操作返回的是原数组的一个视图,对返回结果的改变会直接体现在原数组上
3.2 numpy.transpose(a, axes=None)
numpy.transpose
可以视为 .T
操作的增强版,其除了能够实现数组的转置操作,还能够实现数组任意两个轴之间的变换
- 当参数
axes
缺省时,默认执行的就是数组的转置操作,数组形状由原来的2 * 3 * 4
转变为4 * 3 * 2
,此时与.T
的效果是一样的 - 当参数
axes
非缺省状态下,其值必须是一个 列表或元组,其必须是 (为数组的维度)的一个排列组合,表示原数组轴在新数组轴的位置,比如axes=(1, 2, 0)
表示将原数组的第1
个轴放置在新数组的第0
轴的位置,原数组的第2
个轴放置在新数组的第1
轴的位置,原数组的第0
个轴放置在新数组的第2
轴的位置,从而数组的形状由原来的2*3*4
转变为3 * 4 * 2
3.3 ndarray.transpose(*axes)
等价于 numpy.tramspose(*axes)
,其中 axes
的取值情况也与 numpy.transpose(a, axes=None)
中axes
的取值情况相同。
4. swapaxes
numpy.swapaxes(a, axis1, axis2)
参数
a
:输入数组。axis1, axis2
:整数,表示需要交换的两个轴
ndarray.swapaxes(axis1, axis2)
参数
axis1, axis2
:整数,表示需要交换的两个轴
swapaxes
可以视为 transpose
的一种特殊实现,transpose
可以一次性实现多个轴位置的变换,而 swapaxes
只能实现两个轴位置的变换
- 上述的自由函数与实例方法实现的功能完全相同
-
axis1, axis2
的取值只能是 中的取值,表示数组维度 - 返回结果绝大多数情况下是原数组的一个视图
5. flatten
ndarray.flatten(order='C')
参数
- order:‘C’、‘F’、‘A’、‘K’,可选,缺省值为 ‘C’
flatten
将数组转化为一维数组,就是字面意义上的 拉平
- 该实例方法没有对应的自由函数
- 参数
order
为可选参数,默认为C
,其意义已经在1.4
中解释,在此不再赘述 - 返回数组原数组的副本,并非视图
6. ravel
numpy.ravel(a, order='C')
参数:
a
:数组order
:‘C’、‘F’、‘A’、‘K’,可选,缺省值为 ‘C’
ndarray.ravel(order='C')
参数:
order
:‘C’、‘F’、‘A’、‘K’,可选,缺省值为 ‘C’
-
ravel
实现的功能与flatten
实现的功能相同,都是将数组拉平为一维数组。两者所不同的地方在于,ravel
返回的是数组的一个视图;flatten
返回的是数组的一个副本 - 自由函数和实例方法版本的
ravel
功能相同 - 参数
order
为可选参数,默认为C
,其意义已经在1.4
中解释,在此不再赘述
7. squeeze
numpy.squeeze(a, axis=None)
参数:
- a:数组
- axis:
int或int元组
,可选,缺省值为None
ndarray.squeeze(axis=None)
参数:
- axis:
int或int元组
,可选,缺省值为None
该函数或方法是将数组中长度为1
的轴删除
- 自由函数与实例方法实现的功能相同
-
axis
缺省时,删除数组中所有长度为a
的轴 - 返回数组为原数组的一个视图
axis
取值为int
或int元组
时(在此处不能为int
的列表,否则会报错),会删除指定的轴,但是指定的轴长度必须确实为1
,否则会报错- 如果数组中只有一个元素,在删除了所有长度为
1
的轴后,得到的结果并不是一个标量,而仍然是一个0
维数组,如果想要得到这个标量可以使用ndarray[()]
8. numpy.expand_dims(a, axis)
与 numpy.newaxis
这两个要实现的功能与 squeeze
的功能刚好相反,即在指定的位置添加长度为 1
的轴
8.1 numpy.expand_dims(a, axis)
numpy.expand_dims(a, axis)
参数:
a
:数组axis
:int
或int元组
,表示新轴的位置
- 函数返回的数组是原数组的一个视图
axis
取值不能大于数组当前的维度,否则会报错
此处请注意:
axis
的取值不能大于数组当前的维度,并非不能大于原数组的维度,这种情况出现在axis
为元组时
可以看到,虽然数组
b
的维度为2
,即,但是在c = np.expand_dims(b, (2, 3))
中可以传入(2, 3)
,其原因是当在传入3
之前还有一个2
,此时的维度已经变为了
8.2 numpy.newaxis
numpy.newaxis
既不是自由函数也不是实例方法,而是一个常量,并且np.newaxis is None
的值为True
。
我更愿意把其理解为一个标志,就是说,在其出现的位置就是要增加一个长度为1
的轴,至于其本身是什么含义并不重要
numpy.newaxis
出现在索引的位置,ndarray[numpy.newaxis]
默认在最后一个轴之后添加一个长度为1
的轴- 可以在指定轴位置添加长度为
1
的轴,:
表示此位置不添加新轴 - 返回的数组是原数组的一个视图