我正在创建一个numpy数组列表,然后将其复制到另一个数组以保留原始副本。使用deepcopy()
函数完成复制。当我现在比较两个数组时,它在等价中显示为false。但是当我使用copy()
函数时,这一切都很好。我理解复制和深度复制功能之间的区别,但是等价不一样吗?
那是:
grid1=np.empty([3,3],dtype=object)
for i in xrange(3):
for j in xrange(3):
grid1[i][j] = [i,np.random.uniform(-3.5,3.5,(3,3))]
grid_init=[]
grid_init=copy.deepcopy(grid1)
grid1==grid_init #returns False
grid_init=[]
grid_init=copy.copy(grid1)
grid1==grid_init #returns True
grid_init=[]
grid_init=copy.deepcopy(grid1)
np.array_equal(grid1,grid_init) #returns False
一切都不是真的吗?
答案 0 :(得分:1)
这是我在运行第一个示例时得到的结果:
WARNING:py.warnings:/usr/local/bin/ipython:1: DeprecationWarning: elementwise comparison failed; this will raise the error in the future.
要了解元素比较失败的原因,只需尝试比较单个元素:
grid_init=copy.deepcopy(grid1)
grid_init[0][0] == grid1[0][0]
>>> ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
这会失败,因为列表中的第二个元素本身就是一个numpy数组,并且两个numpy数组的比较不会返回bool(而是一个数组)。
现在,为什么示例案例表现不同?
似乎是一些解释器优化,如果两个对象是相同的,则避免实际的比较逻辑。这两个是同一个对象,因为复制很浅。
grid_init=copy.copy(grid1)
grid_init[0][0] is grid1[0][0]
> True
grid_init[0][0] == grid1[0][0]
> True
根本原因是您正在使用 dtype = object的numpy数组,其中包含列表。这不是一个好主意,可能导致各种奇怪。
相反,您应该只创建2个对齐的数组,一个用于列表中的第一个元素,另一个用于第二个元素。
答案 1 :(得分:0)
我必须运行不同版本的numpy / python,但我得到的错误和/或结果略有不同。仍然存在同样的问题 - 混合数组和列表会产生复杂的结果。
制作2份副本
In [217]: x=copy.copy(grid1)
In [218]: y=copy.deepcopy(grid1)
与浅拷贝相等,通过元素比较给出元素,3x3布尔值:
In [219]: x==grid1
Out[219]:
array([[ True, True, True],
[ True, True, True],
[ True, True, True]], dtype=bool)
元素是2个项目列表:
In [220]: grid1[0,0]
Out[220]:
[0, array([[ 2.08833787, -0.24595155, -3.15694342],
[-3.05157909, 1.83814619, -0.78387624],
[ 1.70892355, -0.87361521, -0.83255383]])]
在浅层副本中,列表ID是相同的。 2个数组具有不同的数据缓冲区(x
不是视图),但它们都指向相同的列表对象(位于记忆中的其他位置)。
In [221]: id(grid1[0,0])
Out[221]: 2958477004
In [222]: id(x[0,0])
Out[222]: 2958477004
使用相同的id
列表相同(它们也满足is
测试)。
In [234]: grid1[0,0]==x[0,0]
Out[234]: True
但使用deepcopy的==
会生成一个简单的False
。这里没有元素比较。我不知道为什么。也许这是numpy
正在发展的领域。
In [223]: y==grid1
Out[223]: False
请注意,deepcopy元素ID是不同的:
In [229]: id(y[0,0])
Out[229]: 2957009900
当我尝试将==
应用于这些数组的元素时,我收到错误:
In [235]: grid1[0,0]==y[0,0]
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
这是SO问题中反复出现的错误,通常是因为人们试图在标量Python上下文中使用布尔数组(来自比较)。
我可以在列表中比较数组:
In [236]: grid1[0,0][1]==y[0,0][1]
Out[236]:
array([[ True, True, True],
[ True, True, True],
[ True, True, True]], dtype=bool)
我可以使用更简单的比较重现ValueError - 2个列表,其中包含一个数组。从表面看,它们看起来是一样的,但由于数组具有不同的ID,因此失败。
In [239]: [0,np.arange(3)]==[0,np.arange(3)]
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
这对比较显示了正在发生的事情:
In [242]: [0,np.arange(3)][0]==[0,np.arange(3)][0]
Out[242]: True
In [243]: [0,np.arange(3)][1]==[0,np.arange(3)][1]
Out[243]: array([ True, True, True], dtype=bool)
Python比较列表的各个元素,然后尝试执行逻辑运算以组合它们all()
。但它无法在all
上执行[True, array([True,True,True])]
。
因此,在我的版本中,y==grid1
会返回False
,因为按元素比较的元素会返回ValueErrors
。这是或者提出错误或警告。他们显然不平等。
总而言之,使用这个数字和数组列表数组,相等测试最终会混合数组操作和列表操作。结果是合乎逻辑的,但很复杂。您必须敏锐地意识到如何比较数组,以及如何比较列表。它们不可互换。
您可以将此数据放入结构化数组中,其中包含dtype
dt = np.dtype([('f0',int),('f1',float,(3,3))])
In [263]: dt = np.dtype([('f0',int),('f1',float,(3,3))])
In [264]: grid2=np.empty([3,3],dtype=dt)
In [265]: for i in range(3):
for j in range(3):
grid2[i][j] = (i,np.random.uniform(-3.5,3.5,(3,3)))
.....:
In [266]: grid2
Out[266]:
array([[ (0,
[[2.719807845330254, -0.6379512247418969, -0.02567206509563602],
[0.9585030371031278, -1.0042751112999135, -2.7805349057485946],
[-2.244526250770717, 0.5740647379258945, 0.29076071288760574]]),
....]])]],
dtype=[('f0', '<i4'), ('f1', '<f8', (3, 3))])
第一个字段,可以使用(给出3x3数组)
获取整数In [267]: grid2['f0']
Out[267]:
array([[0, 0, 0],
[1, 1, 1],
[2, 2, 2]])
第二个字段包含3x3数组,当按字段名访问时,它们是一个4d数组:
In [269]: grid2['f1'].shape
Out[269]: (3, 3, 3, 3)
单个元素是记录(或元组),
In [270]: grid2[2,1]
Out[270]: (2, [[1.6236266210555836, -2.7383730706629636, -0.46604477485902374], [-2.781740733659544, 0.7822732671353201, 3.0054266762730473], [3.3135671425199824, -2.7466097112667103, -0.15205961855874406]])
现在两种副本产生相同的东西:
In [271]: x=copy.copy(grid2)
In [272]: y=copy.deepcopy(grid2)
In [273]: x==grid2
Out[273]:
array([[ True, True, True],
[ True, True, True],
[ True, True, True]], dtype=bool)
In [274]: y==grid2
Out[274]:
array([[ True, True, True],
[ True, True, True],
[ True, True, True]], dtype=bool)
由于grid2
是纯ndarray
(没有中间列表),我怀疑copy.copy
和copy.deepcopy
最终使用grid2.copy()
。在numpy
中,我们通常使用数组复制方法,而不必担心copy
模块。
P.S。似乎dtype=object
,grid1.copy()
与copy.copy(grid1)
相同 - 一个新数组,但是相同的对象指针(即相同的数据)。