形状操作

改变数组的形状#

一个数组的形状是由每个轴的元素数量决定的。可以通过多种方式改变数组的形状,以下介绍常用的函数或方法。

最常用的形状操作是获得一个数组(一般是二维数组)的转置,这种操作可通过 numpy.transpose 函数、ndarray.transpose 方法和 ndarray.T 特征属性实现,这三者是等同的。

import numpy as np
b = np.array([[ 0,  1,  2,  3],
      [10, 11, 12, 13],
      [20, 21, 22, 23],
      [30, 31, 32, 33],
      [40, 41, 42, 43]])

print(np.transpose(b))
print(b.T)
print(b.transpose())
# 以上三行均打印:
# [[ 0 10 20 30 40]
#  [ 1 11 21 31 41]
#  [ 2 12 22 32 42]
#  [ 3 13 23 33 43]]

第二个常用的形状操作是 numpy.ravel 函数及其等价的 ndarray.ravel 方法,该操作返回一个连续的一维扁平数组,其中包含输入数组的所有元素,返回数组的元素类型与输入数组相同。

第三个常用的形状操作是 numpy.reshape 函数及其等价的 ndarray.reshape 方法,该造作返回一个与给定数组具有相同数据的数组,其形状根据输入参数 newshape 确定。新形状 newshape 必须与原来的形状相容(元素个数相同),如果某个维度所给定的值为 -1,则其他维度数将会被自动计算。

numpy.ravel(a, order='C')
numpy.reshape(a, newshape, order='C')

这两种操作中默认值为 'C'order 表示采用 C 语言风格的以行为主的元素索引顺序;另外还有其他 order,请自行查看文档。这两种操作都不改变原来的数组。

import numpy as np

a = np.array([[ 0,  1,  2,  3],
      [10, 11, 12, 13],
      [20, 21, 22, 23]])

print(a.ravel())  # [ 0  1  2  3 10 11 12 13 20 21 22 23]

print(a.reshape(2, 6))
print(np.reshape(a, (2, 6)))
print(a.reshape(2, -1))
print(a.reshape(-1, 6))
# 以上 4 行代码均打印:
# [[ 0  1  2  3 10 11]
#  [12 13 20 21 22 23]]

最后介绍 numpy.resize 函数和ndarray.resize 方法。

numpy.resize 函数返回一个具有指定形状的新数组。不同于 reshaperesize 中给定的形状可以和原数组不兼容(元素数比原数组小或大),如果新给定的形状大于原数组,则新数组将以原数组的内容重复进行填充。该函数不影响原数组。

ndarray.resize 方法并不与 numpy.resize 等价,该方法将直接改变数组的形状和大小(在需要时重新为数组分配内存空间),并且当新形状大于原形状时,多出来的元素将以 0 填充(不是用原数组的内容重复填充)。

numpy.resize(a, new_shape)
ndarray.resize(new_shape, refcheck=True)
import numpy as np
a = np.array([[ 0,  1,  2,  3],
      [ 4,  5,  6,  7],
      [ 8,  9, 10, 11]])

print(np.resize(a, (3, 2)))
# [[0 1]
#  [2 3]
#  [4 5]]
print(np.resize(a, (3, 5)))
# [[ 0  1  2  3  4]
#  [ 5  6  7  8  9]
#  [10 11  0  1  2]]
# 这时 a 并没有改变

a.resize((3, 2))
print(a)
# [[0 1]
#  [2 3]
#  [4 5]]
a.resize(3, 4)
print(a)
# [[0 1 2 3]
#  [4 5 0 0]
#  [0 0 0 0]]

将不同数组堆叠在一起#

多个数组可以沿不同的轴堆叠在一起。常用的函数包括:

  • concatenate:沿现有轴连接一系列数组。
  • stack:沿一个新的轴连接一系列数组。
  • block:从嵌套的块列表中组装一个n 维数组。
  • hstack:在水平方向(按列)堆叠数组。
  • vstack:在垂直方向(按行)堆叠数组。
  • dstack:按深度顺序堆叠数组(沿第三个轴)。
  • column_stack:将一维数组作为列堆叠成二维数组。

以下是使用 hstackvstack 函数进行数组堆叠的示例:

import numpy as np
rng = np.random.default_rng()
a = np.floor(10 * rng.random((2, 2)))
print(a)
# [[4. 9.]
#  [2. 4.]]
b = np.floor(10 * rng.random((2, 2)))
print(b)
# [[5. 6.]
#  [0. 8.]]
print(np.vstack((a, b)))
# [[4. 9.]
#  [2. 4.]
#  [5. 6.]
#  [0. 8.]]
print(np.hstack((a, b)))
# [[4. 9. 5. 6.]
#  [2. 4. 0. 8.]]

将一个数组拆分成几个较小的数组#

与堆叠相反,也可拆分数组。常用的函数包括:

  • split:将一个数组拆分成多个相同大小的子数组,这些子数组都是原数组的视图。当不能等分时,将触发异常。
  • array_split:与 split 相似,但不能等分时不会触发异常。
  • hsplit:将一个数组水平(按列)拆分成多个相同大小的子数组。
  • vsplit:将一个数组水平(按行)拆分成多个相同大小的子数组。
  • dsplit:将一个数组沿第三轴(深度)拆分成多个相同大小的子数组。

以下是使用 hsplit 函数进行数组拆分的示例:

import numpy as np
rng = np.random.default_rng()
a = np.floor(10 * rng.random((2, 12)))
print(a)
# [[5. 2. 5. 2. 8. 4. 9. 4. 6. 3. 3. 0.]
#  [6. 8. 0. 0. 9. 4. 4. 0. 0. 3. 9. 5.]]
print(np.hsplit(a, 3))
# [array([[5., 2., 5., 2.],
#        [6., 8., 0., 0.]]), array([[8., 4., 9., 4.],
#        [9., 4., 4., 0.]]), array([[6., 3., 3., 0.],
#        [0., 3., 9., 5.]])]
print(np.hsplit(a, (3, 4)))
# [array([[5., 2., 5.],
#        [6., 8., 0.]]), array([[2.],
#        [0.]]), array([[8., 4., 9., 4., 6., 3., 3., 0.],
#        [9., 4., 4., 0., 0., 3., 9., 5.]])]
基础知识拷贝和视图