首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >python复制模块中copy.copy和copy.deepcopy的等价性

python复制模块中copy.copy和copy.deepcopy的等价性
EN

Stack Overflow用户
提问于 2016-01-16 06:11:30
回答 2查看 1K关注 0票数 2

我正在创建一个numpy数组列表,然后将其复制到另一个数组中,以保存原始副本。使用deepcopy()函数完成复制。当我现在比较这两个数组时,它在等价性上是错误的。但是,当我使用copy()函数时,.I理解了复制函数和深度复制函数之间的区别,但其等价性是否是相同的呢?

这就是:

代码语言:javascript
复制
 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

难道一切都不是真的吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-01-16 07:42:16

我一定在运行numpy/python的不同版本,但是我得到的错误和/或结果略有不同。同样的问题也同样适用--混合数组和列表会产生复杂的结果。

复制这两份

代码语言:javascript
复制
In [217]: x=copy.copy(grid1)
In [218]: y=copy.deepcopy(grid1)

与浅拷贝相等,给出一个逐元素比较的元素,一个3x3布尔值:

代码语言:javascript
复制
In [219]: x==grid1
Out[219]: 
array([[ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True]], dtype=bool)

元素是两个项目列表:

代码语言:javascript
复制
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]])]

在浅拷贝中,列表in是相同的。这两个数组具有不同的数据缓冲区(x不是视图),但它们都指向相同的列表对象(位于记忆中的其他位置)。

代码语言:javascript
复制
In [221]: id(grid1[0,0])
Out[221]: 2958477004
In [222]: id(x[0,0])
Out[222]: 2958477004

对于相同的id,列表是相等的(它们还满足is测试)。

代码语言:javascript
复制
In [234]: grid1[0,0]==x[0,0]
Out[234]: True

但是,带有深度拷贝的==产生了一个简单的False。这里没有逐个元素的比较。我不知道为什么。也许这是numpy正在开发的一个领域。

代码语言:javascript
复制
In [223]: y==grid1
Out[223]: False

请注意,深度复制元素ids是不同的:

代码语言:javascript
复制
In [229]: id(y[0,0])
Out[229]: 2957009900

当我试图将==应用于这些数组的一个元素时,我会得到一个错误:

代码语言:javascript
复制
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()

这是在这样的问题中反复出现的错误,通常是因为人们试图在标量Python上下文中使用布尔数组(来自比较)。

我可以将数组与列表中的数组进行比较:

代码语言:javascript
复制
In [236]: grid1[0,0][1]==y[0,0][1]
Out[236]: 
array([[ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True]], dtype=bool)

我可以使用更简单的比较-2列表来再现ValueError,其中包含一个数组。表面上,它们看起来是一样的,但是由于数组有不同的it,所以失败了。

代码语言:javascript
复制
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()

这对比较显示了正在发生的事情:

代码语言:javascript
复制
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

代码语言:javascript
复制
 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数组)。

代码语言:javascript
复制
In [267]: grid2['f0']
Out[267]: 
array([[0, 0, 0],
       [1, 1, 1],
       [2, 2, 2]])

第二个字段包含3x3数组,当按字段名访问时,这些数组是一个4d数组:

代码语言:javascript
复制
In [269]: grid2['f1'].shape
Out[269]: (3, 3, 3, 3)

单个元素是记录(或元组),

代码语言:javascript
复制
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]])

现在这两种拷贝产生的东西是一样的:

代码语言:javascript
复制
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.copycopy.deepcopy最终使用了grid2.copy()。在numpy中,我们通常使用数组复制方法,而不必费心使用copy模块。

附注:使用dtype=objectgrid1.copy()似乎与copy.copy(grid1)相同--一个新的数组,但对象指针相同(即相同的数据)。

票数 0
EN

Stack Overflow用户

发布于 2016-01-16 06:24:32

这就是我在运行第一个示例时得到的结果:

代码语言:javascript
复制
WARNING:py.warnings:/usr/local/bin/ipython:1: DeprecationWarning: elementwise comparison failed; this will raise the error in the future.

要了解元素级比较失败的原因,只需尝试比较单个元素:

代码语言:javascript
复制
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 (而是一个数组)。

那么,为什么这个例子表现得不同呢?

似乎是一些解释器优化,避免了实际的比较逻辑,如果这两个对象是相同的。这两个对象是同一个对象,因为复制比较浅。

代码语言:javascript
复制
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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34824110

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档