【问题标题】:Numpy deep copy still altering original arrayNumpy 深拷贝仍在改变原始数组
【发布时间】:2019-05-21 05:33:13
【问题描述】:

据我了解,ndarray 的深层副本应该创建 ndarray 的第二次迭代,以便更改任何一个数组都不会影响另一个数组的内容。但是,在下面的代码中,我原来的 ndarray 发生了变化:

print(data[3])   #[array([[0.00000000e+00, 3.29530000e+04],
   #[4.00066376e-04, 3.29530000e+04],
   #[8.00132751e-04, 3.29530000e+04],
   #...,
   #[1.28784461e+03, 3.47140000e+04],
   #[1.28784621e+03, 3.57750000e+04],
   #[1.28785381e+03, 1.92450000e+04]]),
   #'CH4.VDC1']

new = np.empty_like(data)
new[:] = data
new[3][0][:,1] = 4/16421 * (data[3][0][:,1] - 33563)

print(data[3])  #[array([[ 0.00000000e+00, -1.48590220e-01],
   #[ 4.00066376e-04, -1.48590220e-01],
   #[ 8.00132751e-04, -1.48590220e-01],
   #...,
   #[ 1.28784461e+03,  2.80372694e-01],
   #[ 1.28784621e+03,  5.38822240e-01],
   #[ 1.28785381e+03, -3.48772913e+00]]),
   #'CH4.VDC1']

数组是一个混合类型的 (5,2) 数组,里面有一个 (largenumber,2) 子数组。我只是想更改子数组,但我想知道深层副本是否也扩展到该子数组。我跑了

np.shares_memory(new, data) #false

np.might_share_memory(new,data) #false

注意我在 jupyter notebook 中运行它可能也很重要。虽然我无法想象为什么它会改变任何东西。您可以使用以下方法重新创建数据:

np.array([[[[0.00000000e+00, 2.82540000e+04],
[4.00066376e-04, 2.82530000e+04],
[8.00132751e-04, 2.82520000e+04],
[1.28784461e+03, 4.61170000e+04],
[1.28784621e+03, 3.38280000e+04],
[1.28785381e+03, 3.38230000e+04]],
'CH1.Bx'],
[[[0.00000000e+00, 2.00400000e+04],
[4.00066376e-04, 2.00400000e+04],
[8.00132751e-04, 2.00410000e+04],
[1.28784461e+03, 1.81600000e+04],
[1.28784621e+03, 1.80830000e+04],
[1.28785381e+03, 4.80200000e+03]],
'CH2.By'],
[array([[0.00000000e+00, 3.82520000e+04],
[4.00066376e-04, 3.82510000e+04],
[8.00132751e-04, 3.82510000e+04],
[1.28784461e+03, 3.42810000e+04],
[1.28784621e+03, 3.42820000e+04],
[1.28785381e+03, 3.40380000e+04]]),
'CH3.Bz'],
[[[ 0.00000000e+00, -1.48590220e-01],
[ 4.00066376e-04, -1.48590220e-01],
[ 8.00132751e-04, -1.48590220e-01],
[ 1.28784461e+03,  2.80372694e-01],
[ 1.28784621e+03,  5.38822240e-01],
[ 1.28785381e+03, -3.48772913e+00]],
'CH4.VDC1'],
[[[0.00000000e+00, 3.26760000e+04],
[4.00066376e-04, 3.26760000e+04],
[8.00132751e-04, 3.26750000e+04],
[1.28784981e+03, 3.40450000e+04],
[1.28785061e+03, 3.40420000e+04],
[1.28785141e+03, 3.40390000e+04]],
'CH5.VDC2']], dtype=object)`

【问题讨论】:

  • 你能分享整个data以便重现这个吗?
  • 您的对象 dtype 数组包含对内存中其他地方的对象的引用。适用于普通数值数组的复制级别不会复制这些对象。

标签: python numpy multidimensional-array deep-copy


【解决方案1】:

这看起来不像您从那里开始的数组。目前尚不清楚data 是什么,但data[3] 是一个包含数组和字符串的2 元素列表,由此判断,data 可能是另一个列表,或者可能是一个object-dtype 数组。

您对深拷贝的尝试:

new = np.empty_like(data)
new[:] = data

不是深拷贝。它将是大多数普通数组的副本(对于大多数数组来说,深/浅是等效的),但不是列表的深副本,也不是 object-dtype 数组的深副本。它将创建一个新的 object-dtype 数组,并用 data 的单元格引用的相同对象的引用填充它。

您可能应该选择一种更好的方式来组织您的数据。这种数据结构不是使用 NumPy 的有效方式,它会导致更多的问题。也就是说,如果你想深度复制它,copy.deepcopy 可能是你最好的选择。

【讨论】:

    【解决方案2】:

    你应该使用copy's deepcopy,[:] 不做深拷贝:

    In [11]: a = [[1], 2]
    
    In [12]: b = a[:]
    
    In [13]: from copy import deepcopy
        ...: c = deepcopy(a)
    
    In [14]: b[0].append(3)
    
    In [15]: a
    Out[15]: [[1, 3], 2]
    
    In [16]: c
    Out[16]: [[1], 2]
    

    【讨论】:

    • 但是in the documentation,它暗示 np.copy 是一个深拷贝。那么我真的需要退出 numpy 来做到这一点吗?
    • @Bob 与 python 列表相比,[:] 不复制数组。您不会在代码中的任何地方使用np.copynp.copy 是一个副本,虽然我不认为它会深度复制任意对象,但对于数值来说它应该可以正常工作。
    • @BobSherwin 链接里没看到,我只是测试了一下,不是深拷贝。
    • 我明白了。所以我想它一定是一个浅拷贝。 This tutorial 似乎有问题。 @jan [:] 不复制,但初始创建应该是正确的?
    • @BobSherwin 我认为如果它是一个单一的 dtype 数组(一个“正确的”numpy 数组),如果它是一个对象数组(甚至是 numpy 对象),它就不会进行深度复制。这是 OP 的情况(numpy 数组中的 numpy 数组)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-30
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多