在使用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参数,不太容易区分

为什么numpy的resize函数没有最近邻插值_取值


为什么numpy的resize函数没有最近邻插值_转置_02

1.2 reshape返回的是数组的一个视图(可能)

如果对reshape返回的结果进行修改,原数组也会在相应位置进行修改
其实官方文档上说的是:如果可能的话,会返回一个视图,否则将是一个数组的副本,所以说就是不保证一定是一个视图
其实这话说了一点用也没有,也没有说到底啥时候返回一个视图,啥时候返回一个副本,不过我使用的时候还没有遇到不是副本的情况,可能没有遇到特殊情况吧

为什么numpy的resize函数没有最近邻插值_数组_03

1.3 关于参数new_shape

new_shape的取值是必须的,不能省略,有以下三种情况:(假设数组元素总数为N)

  • 为什么numpy的resize函数没有最近邻插值_数组_04,且 为什么numpy的resize函数没有最近邻插值_numpy_05
    也就是说,各维度的长度乘积要把数组中的值一个不漏地安排完
  • 为什么numpy的resize函数没有最近邻插值_取值_06
    也就说,可以允许一个维度上的取值为 -1,至于该维度上的长度究竟是多少,由numpy自己推算,原则还是那一条:所有数据必须一个不能少
  • 为什么numpy的resize函数没有最近邻插值_数组_07
    当参数值为一个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 拉成一个一维数组,那么最终的结果是为什么numpy的resize函数没有最近邻插值_取值_08还是为什么numpy的resize函数没有最近邻插值_numpy_09呢?绝大多数人的思维惯性会认为答案是前者,可是答案有没有可能是后者呢?是有可能的!order参数就是来解决这个问题的。

为什么numpy的resize函数没有最近邻插值_数组_10

order缺省情况下,取值为C,即首先按照 来读取元素,进而实现重塑;而当取值为F时,即首先按照 来读取元素,进而实现重塑,就得到了上文中提到的第二种结果

推广到高维数组 为什么numpy的resize函数没有最近邻插值_numpy_11order参数取值为C表示首先按照 为什么numpy的resize函数没有最近邻插值_数组_12 来读取元素,其次是 为什么numpy的resize函数没有最近邻插值_numpy_13 ,依次到最后一个是 为什么numpy的resize函数没有最近邻插值_数组_14;取值为 F 时刚好相反,首先按照 为什么numpy的resize函数没有最近邻插值_数组_14 来读取元素,其次是 为什么numpy的resize函数没有最近邻插值_numpy_16 ,依次到最后一个是 为什么numpy的resize函数没有最近邻插值_数组_12

numpy中的很多函数都有这个参数,大多数都是这个含义
其实我们一般都习惯缺省值,思维习惯吧。


2. resize

2.1 np.rersize

ndarray.resize(a, new_shape)

参数

  • a:要调整大小的数组。
  • new_shapeintint的元组,要生成的数组的形状

注意:如果新数组元素数目多于原始数组元素数目(a),多余部分将重复填充 a

为什么numpy的resize函数没有最近邻插值_numpy_18

  • np.resize 函数几乎可以覆盖 reshape 函数的功能,但是new_shape中任一维度的取值均不能为-1;
  • 当目标数组元素多余原始数组元素个数时,使用原始数组中的元素逐个填充,且是按照 C 顺序填充;
  • np.resize返回的结果数组不是原始数组的视图

为什么numpy的resize函数没有最近邻插值_numpy_19

2.2 ndarray.resize

ndarray.resize(new_shape, refcheck=True)
参数

  • new_shapeintint的元组,要生成的数组的形状
  • refcheck:可选的布尔值, 如果为false,则不检查引用计数。默认值为true

注意:此方法就地更改数组的形状和大小;如果新数组元素数目多于原始数组元素数目(a),多余部分将用零填充,而不是重复复制 a

  • a.resize 方法就地改变 数组a,没有返回值
  • refcheck参数默认缺省为true,此时一般会报错,这个错误也是搞的一头雾水;但是当设置参数refcheckfalse时,就会得到想要得到的数组,并且以0填充多余的位置

2.3 总结

说实话,知道这次整理数组重塑的相关方法时候才发现原来numpy中还有一个这样的函数(之前用opencv中的resize函数比较多)。并且该函数改变了数组的内容,并不是一般意义上的数组的重塑,不过或许其能够自动补充元素的功能会在之后有机会用到吧。


3. transpose

numpy.transpose(a, axes=None)
参数

  • a:输入数组。
  • axes:元组或整数列表,可选

ndarray.transpose(*axes)
参数

  • axes :元组或整数列表,可选

3.1 数组的转置

其实,numpy中的这个transpose函数对应的是数学概念中的数组的转置,转置的概念在二维层面很好理解,就是把行列调换位置呗,为什么numpy的resize函数没有最近邻插值_取值_20变为为什么numpy的resize函数没有最近邻插值_取值_21即可。但是,当数组超过二维时候,数组的这个转置概念就会变得比较抽象,理解起来也比较困难,所以此处就是就功能而言,不再涉及具体的数学概念,高维情况下比较多的是三维(opencv)和四维(深度学习中的tensor)等。

  • a.T 可以很简单的实现数组的转置
    可以看到数组b由原来的4*6转置为6*4
  • 为什么numpy的resize函数没有最近邻插值_取值_22


  • 对高维数组进行 .T 操作,会将所有的轴顺序倒序排列
    数组 d 由原来的 2 * 3 * 4 变为 4 * 3 * 2
  • 为什么numpy的resize函数没有最近邻插值_取值_23


  • .T 操作返回的是原数组的一个视图,对返回结果的改变会直接体现在原数组上

3.2 numpy.transpose(a, axes=None)

numpy.transpose可以视为 .T 操作的增强版,其除了能够实现数组的转置操作,还能够实现数组任意两个轴之间的变换

为什么numpy的resize函数没有最近邻插值_转置_24

  • 当参数 axes 缺省时,默认执行的就是数组的转置操作,数组形状由原来的 2 * 3 * 4 转变为 4 * 3 * 2,此时与 .T 的效果是一样的
  • 当参数 axes 非缺省状态下,其值必须是一个 列表或元组,其必须是 为什么numpy的resize函数没有最近邻插值_取值_25(为什么numpy的resize函数没有最近邻插值_数组_07为数组的维度)的一个排列组合,表示原数组轴在新数组轴的位置,比如 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 的取值只能是 为什么numpy的resize函数没有最近邻插值_数组_27中的取值,为什么numpy的resize函数没有最近邻插值_数组_07表示数组维度
  • 返回结果绝大多数情况下是原数组的一个视图

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 的轴
  • 返回数组为原数组的一个视图

为什么numpy的resize函数没有最近邻插值_转置_29

  • axis 取值为 intint元组时(在此处不能为 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:数组
  • axisintint元组,表示新轴的位置
  • 函数返回的数组是原数组的一个视图
  • axis 取值不能大于数组当前的维度,否则会报错

此处请注意:axis的取值不能大于数组当前的维度,并非不能大于原数组的维度为什么numpy的resize函数没有最近邻插值_数组_07,这种情况出现在axis为元组时

为什么numpy的resize函数没有最近邻插值_转置_31

可以看到,虽然数组 b的维度为2,即为什么numpy的resize函数没有最近邻插值_numpy_32,但是在 c = np.expand_dims(b, (2, 3)) 中可以传入(2, 3),其原因是当在传入 3 之前还有一个 2,此时的维度已经变为了 为什么numpy的resize函数没有最近邻插值_取值_33


8.2 numpy.newaxis

numpy.newaxis 既不是自由函数也不是实例方法,而是一个常量,并且 np.newaxis is None 的值为 True
我更愿意把其理解为一个标志,就是说,在其出现的位置就是要增加一个长度为 1 的轴,至于其本身是什么含义并不重要

  • numpy.newaxis出现在索引的位置,ndarray[numpy.newaxis] 默认在最后一个轴之后添加一个长度为1的轴
  • 可以在指定轴位置添加长度为1的轴,: 表示此位置不添加新轴
  • 返回的数组是原数组的一个视图