在 Numpy 中,reshape 函数使用修改后的形状返回其参数,而 ndarray.resize 方法修改数组本身。但这到底意味着什么?真正的区别是什么?
import numpy as np
a = np.arange(18)
b = a.reshape(3,6)
a.resize(3,6)
a[0] = -2
print(a)
[[-2 -2 -2 -2 -2 -2]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]]
print(b)
[[-2 -2 -2 -2 -2 -2]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]]
b[0]= -1
print(b)
[[-1 -1 -1 -1 -1 -1]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]]
print(a)
[[-1 -1 -1 -1 -1 -1]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]]
从上面的代码中,resize() 和 reshape() 对相同的数据执行相同的操作。为什么需要其中两个?
In [15]: a = np.arange(18)
...: b = a.reshape(3,6)
我喜欢用以下命令检查数组的属性:
In [16]: a.__array_interface__
Out[16]:
{'data': (65611776, False),
'strides': None,
'descr': [('', '<i8')],
'typestr': '<i8',
'shape': (18,),
'version': 3}
In [17]: b.__array_interface__
Out[17]:
{'data': (65611776, False),
'strides': None,
'descr': [('', '<i8')],
'typestr': '<i8',
'shape': (3, 6),
'version': 3}
请注意,两者的data
相同。b
是a
的view
。 它是一个新的数组对象,但它共享基础数据缓冲区。 它的形状不同,但对a
的变化将显示为b
的变化(反之亦然)。
查看有关view
与copy
的文档。 这是numpy
的一个重要区别,所以你需要很好地理解它。
有时reshape
必须返回副本,例如更改order
。 同样重要的是要认识到reshape
不能改变元素的数量。
还有一个reshape
函数,在大多数情况下与该方法相同。
shape
属性也可以直接更改:
In [19]: a.shape = (6,3)
In [20]: a
Out[20]:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]])
In [21]: b
Out[21]:
array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17]])
该操作已就地修改a
本身。 它比reshape
更严格一些,并且不经常使用。 例如,我们可以用一行b
:
b = np.arange(18).reshape(3,6)
resize
的主要区别在于它可以更改元素的数量。 它可以截断,也可以增加大小。resize
方法和函数都执行此操作,但具有不同的"填充"规则。resize
方法就地运行。
在您的示例中,a.resize(3,6)
就地更改了a
,更改了其shape
,但没有更改其数据缓冲区或b
到该缓冲区的链接。 所以对a
的变化也表现为b
的变化。
就地shape
更改后的a
仍然具有相同的data
:
In [22]: a.__array_interface__
Out[22]:
{'data': (65611776, False),
'strides': None,
'descr': [('', '<i8')],
'typestr': '<i8',
'shape': (6, 3),
'version': 3}
以及resize
方法后的相同data
。
In [23]: a.resize(3,6)
In [24]: a.__array_interface__
Out[24]:
{'data': (65611776, False),
'strides': None,
'descr': [('', '<i8')],
'typestr': '<i8',
'shape': (3, 6),
'version': 3}
请注意,如果我尝试以更改元素总数的方式resize
a
,则会出现错误。 那是因为b
共享数据缓冲区,我们无法在不影响b
大小的情况下更改a
的大小。
In [28]: a.resize(4,6)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-28-f7d47a627631> in <module>
----> 1 a.resize(4,6)
ValueError: cannot resize an array that references or is referenced
by another array in this way.
Use the np.resize function or refcheck=False
我想你会发现np.reshape
和a.reshape
被使用了很多。 这两种形式的resize
几乎都不经常使用。reshape
更可预测、更安全。resize
也可以做同样的事情,但它也可以让你做危险的事情。
我将专注于了解view
和copy
之间的区别,其次是创建新数组和就地更改之间的区别。
这意味着一个函数将修改数组,而您只会拥有修改后的数组。
另一个将返回一个新数组,修改后,但保留原始数组不变。它将使用双倍的内存,但原始数组将可用于其他计算。
根据具体情况,您可能更喜欢其中一种。
我认为这最好通过示例来解释。
import numpy as np
a = np.arange(18)
b = a
print(a)
# [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17]
print(b)
# [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17]
print("Reshape - doesnt change the base array")
print(a.reshape(3,6))
#[[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]]
print(b)
# [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17]
b = a.reshape(3,6)
print(a)
# [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17]
print(b)
#[[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]]
a = np.arange(18)
b = a
print(a)
# [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17]
print(b)
# [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17]
print("resize changes the actual base array")
a.resize(3,6)
print(a)
#[[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]]
print(b)
#[[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]]