说明
NumPy 教程 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
本文将介绍如果对一个原始数组改变其形状,即修改行列数、维度等操作,同时也包括对数组的一些变形。
NumPy 常用的数据变形操作有:
方法 | 说明 |
---|---|
np.reshape(shape[, order]) | 返回包含具有新形状的相同数据的数组 |
np.resize(new_shape[, refcheck]) | 更改阵列的形状和大小,重新分配内存 |
np.transpose(*axes) | 返回轴已转置的数组视图(view) |
np.swapaxes(axis1, axis2) | 返回轴1与轴2水平互换后的视图(view) |
np.flatten([order]) | 返回折叠为一维的数组的副本 |
np.ravel([order]) | 返回展平数组 |
np.squeeze([axis]) | 从数组的形状中删除单维条目 |
NumPy 提供了 numpy.reshape 和 ndarray.reshape 两个层面的变形方法,它的实现的效果是一样的,返回包含具有新形状的相同数据的数组。新形状应与原形状兼容。
arr = np.arange(6)
# array([0, 1, 2, 3, 4, 5])
arr.reshape(2, 3) # 变形为2行3列
'''
array([[0, 1, 2],
[3, 4, 5]])
'''
arr.reshape(3, 2) # 变形为3行2列
'''
array([[0, 1],
[2, 3],
[4, 5]])
'''
arr.reshape(6, 1) # 变形为6行1列
'''
array([[0],
[1],
[2],
[3],
[4],
[5]])
'''
如果正整数(也可以是负数),则结果将是该长度的一维数组。
np.arange(6).reshape((3, 2))
'''
array([[0, 1],
[2, 3],
[4, 5]])
'''
a = np.array([[1,2,3], [4,5,6]])
a
'''
array([[1, 2, 3],
[4, 5, 6]])
'''
# 以下方法只管指定行列数,其他位置用-1,会自动计算
a.reshape([-1, 3]) # 要3列
a.reshape([2, -1]) # 要两行,效果相同
a.reshape(6) # 一维,6列
a.reshape(-1) # 同上
# array([1, 2, 3, 4, 5, 6])
a.reshape([3,2]) # 转为3行两列
'''
array([[1, 2],
[3, 4],
[5, 6]])
'''
a.reshape([2, 4]) # 报错,形状无法兼容
# Traceback (most recent call last) ----> 1 a.reshape([2, 4])
# ValueError: cannot reshape array of size 6 into shape (2,4)
ndarray.reshape
与自由函数 numpy.reshape
不同的是,ndarray 上的此方法允许将 shape 参数的元素作为单独的参数传入。例如,a.reshape(10, 11)
等同于 a.reshape((10, 11))
。
也可以通过给 shape 属性赋值的方法改变形状:
a.shape = (3, 2)
a
'''
array([[1, 2],
[3, 4],
[5, 6]])
'''
在不复制数据的情况下更改数组的形状并不总是可能的。如果要在复制数据时引发错误,应将新形状指定给数组的形状属性。
>>> a = np.zeros((10, 2))
# 转置使数组不连续
>>> b = a.T
# 使用视图可以在不修改初始对象的情况下修改形状
>>> c = b.view()
>>> c.shape = (20)
'''
AttributeError: Incompatible shape for in-place modification. Use
`.reshape()` to make a copy with the desired shape.
'''
order关键字给出了索引顺序,用于从数组中获取值,然后将值放入输出数组。例如,假设您有一个数组:
a = np.arange(6).reshape((3, 2))
a
'''
array([[0, 1],
[2, 3],
[4, 5]])
'''
您可以将重塑视为首先散开数组(使用给定的索引顺序),然后使用与散开相同的索引顺序将散开数组中的元素插入到新数组中。
np.reshape(a, (2, 3)) # C-like 索引顺序
'''
array([[0, 1, 2],
[3, 4, 5]])
'''
np.reshape(np.ravel(a), (2, 3)) # 相当于 C ravel 然后 C 重塑
'''
array([[0, 1, 2],
[3, 4, 5]])
'''
np.reshape(a, (2, 3), order='F') # Fortran-like 索引顺序
'''
array([[0, 4, 3],
[2, 1, 5]])
'''
np.reshape(np.ravel(a, order='F'), (2, 3), order='F')
'''
array([[0, 4, 3],
[2, 1, 5]])
'''
numpy.resize(a, new_shape)
和 ndarray.resize(new_shape, refcheck=True)
等同的作用,numpy.resize
如果新数组比原始数组大,则新数组中会填充 a 的重复副本。请注意,此行为与 ndarray.resize
不同,后者填充 0 而不是 a 的重复副本。
resize 将在必要时为数据区域重新分配空间。只能调整连续数组(内存中连续的数据元素)的大小。引用计数检查(refcheck)的目的是确保不要将此数组用作另一个 Python 对象的缓冲区重新分配内存。但是,引用计数可以通过其他方式增加,因此如果您确定没有与另一个 Python 对象共享此数组的内存,那么可以安全地将 refcheck 设置为 False。
当数组的总大小不变时,应使用 reshape。在大多数其他情况下,索引(减小)或填充(增大)可能是更合适的解决方案。
a=np.array([[0,1],[2,3]])
np.resize(a,(2,3))
'''
array([[0, 1, 2],
[3, 0, 1]])
'''
np.resize(a,(1,4))
# array([[0, 1, 2, 3]])
np.resize(a,(2,4))
'''
array([[0, 1, 2, 3],
[0, 1, 2, 3]])
'''
缩小数组:数组被展平(按数据存储在内存中的顺序)、调整大小和形状:
a = np.array([[0, 1], [2, 3]], order='C')
a.resize((2, 1))
a
'''
array([[0],
[1]])
'''
a2 = np.array([[0, 1], [2, 3]], order='F')
a2.resize((2, 1))
a2
'''
array([[0],
[2]])
'''
放大数组:如上所述,但缺少的条目用零填充:
b = np.array([[0, 1], [2, 3]])
b.resize(2, 3) # 新的形状参数不必是元组
b
'''
array([[0, 1, 2],
[3, 0, 0]])
'''
# 引用数组会阻止调整大小…
c = a
a.resize((1, 1))
'''
Traceback (most recent call last):
...
ValueError: cannot resize an array that references or is referenced ...
'''
# 除非refcheck为False:
a.resize((1, 1), refcheck=False)
a
# array([[0]])
c
# array([[0]])
resize 和 reshape 的区别:
对矩阵进行转置,ndarray.transpose(*axes)
和 ndarray.T
效果一样。对于一维数组,这没有任何影响,因为转置向量只是同一个向量。要将一维数组转换为二维列向量,必须添加额外的维数,如 np.atleast2d(a)
。.T
的操作相当于 a[:, np.newaxis]
。
对于二维数组,这是标准的矩阵转置。对于 n-D 数组,如果给定轴,则它们的顺序指示轴的排列方式(参见示例)。如果未提供轴则:
a.shape = (i[0], i[1], ... i[n-2], i[n-1])
a.transpose().shape = (i[n-1], i[n-2], ... i[1], i[0])
参数 axes 有 None, tuple of ints, or n ints
:
例子:
a = np.array([[1, 2], [3, 4]])
a
'''
array([[1, 2],
[3, 4]])
'''
a.transpose()
'''
array([[1, 3],
[2, 4]])
'''
a.transpose((1, 0))
'''
array([[1, 3],
[2, 4]])
'''
a.transpose(1, 0)
'''
array([[1, 3],
[2, 4]])
'''
# T 操作
x = np.array([[1.,2.],[3.,4.]])
x
'''
array([[ 1., 2.],
[ 3., 4.]])
'''
x.T
'''
array([[ 1., 3.],
[ 2., 4.]])
'''
x = np.array([1.,2.,3.,4.])
x
# array([ 1., 2., 3., 4.])
x.T
# array([ 1., 2., 3., 4.])
numpy.swapaxes(a, axis1, axis2)
和 ndarray.swapaxes(axis1, axis2)
的操作是等价的,返回交换了 axis1 和 axis2 的数组视图。对于 NumPy>=1.10.0,如果 a 是ndarray,则返回 a 的视图;否则将创建一个新数组。对于早期的 NumPy 版本,仅当轴的顺序更改时才返回视图,否则返回输入数组。
x = np.array([[1,2,3]])
np.swapaxes(x,0,1)
'''
array([[1],
[2],
[3]])
'''
x = np.array([[[0,1],[2,3]],[[4,5],[6,7]]])
x
'''
array([[[0, 1],
[2, 3]],
[[4, 5],
[6, 7]]])
'''
np.swapaxes(x,0,2)
'''
array([[[0, 4],
[2, 6]],
[[1, 5],
[3, 7]]])
'''
ndarray.flatten(order='C')
返回折叠为一维的数组的副本,order 参数可选 {‘C’, ‘F’, ‘A’, ‘K’}。
a = np.array([[1,2], [3,4]])
a.flatten()
# array([1, 2, 3, 4])
a.flatten('F')
# array([1, 3, 2, 4])
“C”表示按行为主(C样式)顺序展平。“F”表示按列为主(Fortran 样式)顺序展平。“A”表示如果A在内存中是连续的,则按列为主顺序展平,否则按行为主顺序展平。“K”表示按元素在内存中出现的顺序将 a展平。默认值为“C”。
numpy.ravel(a, order='C')
如同 ndarray.ravel([order])
返回一个连续的扁平数组,包含输入元素的一维数组。只有在需要时才生成副本。从 numpy1.10 开始,返回的数组将具有与输入数组相同的类型,例如,将为屏蔽数组输入返回屏蔽数组。
在两个维度中,行索引变化最慢,列索引变化最快。这可以推广到多个维度,其中行的主要顺序意味着沿第一个轴的索引变化最慢,沿最后一个轴的索引变化最快。相反的情况适用于列主索引,Fortran风格的索引排序。在需要视图时,排列重塑(-1)可能更可取。
x = np.array([[1, 2, 3], [4, 5, 6]])
# 等同于 reshape(-1, order=order)
np.ravel(x)
# array([1, 2, 3, 4, 5, 6])
x.reshape(-1)
# array([1, 2, 3, 4, 5, 6])
np.ravel(x, order='F')
# array([1, 4, 2, 5, 3, 6])
# 当顺序为“A”时,它将保留数组的“C”或“F”顺序
np.ravel(x.T)
# array([1, 4, 2, 5, 3, 6])
np.ravel(x.T, order='A')
# array([1, 2, 3, 4, 5, 6])
# 当顺序为“K”时,它将保留既不是“C”也不是“F”的顺序,但不会反转轴
a = np.arange(3)[::-1]
a
# array([2, 1, 0])
a.ravel(order='C')
# array([2, 1, 0])
a.ravel(order='K')
# array([2, 1, 0])
a = np.arange(12).reshape(2,3,2).swapaxes(1,2)
a
'''
array([[[ 0, 2, 4],
[ 1, 3, 5]],
[[ 6, 8, 10],
[ 7, 9, 11]]])
'''
a.ravel(order='C')
# array([ 0, 2, 4, 1, 3, 5, 6, 8, 10, 7, 9, 11])
a.ravel(order='K')
# array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
ndarray.squeeze(axis=None)
和 numpy.squeeze(a, axis=None)[source]
从数组的形状中删除单维度条目,即把 shape 中为1的维度去掉。将输入的数组删除长度为1的所有维度或维度的子集。这始终是a本身或a中的视图。请注意,如果压缩所有轴,则结果是0d数组而不是标量。
x = np.array([[[0], [1], [2]]])
x.shape
# (1, 3, 1)
np.squeeze(x).shape
# (3,)
np.squeeze(x, axis=0).shape
# (3, 1)
np.squeeze(x, axis=1).shape
'''
Traceback (most recent call last):
...
ValueError: cannot select an axis to squeeze out
which has size not equal to one
'''
np.squeeze(x, axis=2).shape
# (1, 3)
x = np.array([[1234]])
x.shape
# (1, 1)
np.squeeze(x)
# array(1234) # 0d array
np.squeeze(x).shape
# ()
np.squeeze(x)[()]
# 1234
更新时间:Jan. 29, 2021, 10:46 a.m. 标签:numpy shape