Arrays 为什么deepcopy会更改numpy数组的值?
我遇到了一个问题,在使用copy.deepcopy或Numpy.copy复制Numpy数组后,Numpy数组中的值会发生变化。事实上,如果我只是在复制数组之前先打印它,我会得到不同的值 我使用的是Python 3.5、Numpy 1.11.1和Scipy 0.18.0 我的起始数组包含在元组列表中;每个元组都是成对的:一个浮点(一个时间点)和一个numpy数组(该时间点的ODE解决方案),例如: 在本例中,我需要最后一个时间点的数组 当我调用以下命令时:Arrays 为什么deepcopy会更改numpy数组的值?,arrays,numpy,scipy,copy,ode,Arrays,Numpy,Scipy,Copy,Ode,我遇到了一个问题,在使用copy.deepcopy或Numpy.copy复制Numpy数组后,Numpy数组中的值会发生变化。事实上,如果我只是在复制数组之前先打印它,我会得到不同的值 我使用的是Python 3.5、Numpy 1.11.1和Scipy 0.18.0 我的起始数组包含在元组列表中;每个元组都是成对的:一个浮点(一个时间点)和一个numpy数组(该时间点的ODE解决方案),例如: 在本例中,我需要最后一个时间点的数组 当我调用以下命令时: tandy = c1.Integrate
tandy = c1.IntegrateColony(3)
ylast = copy.deepcopy(tandy[-1][1])
print(ylast)
tandy = c1.IntegrateColony(3)
print(tandy[-1][1])
ylast = copy.deepcopy(tandy[-1][1])
print(ylast)
我得到了一些对我试图模拟的系统有意义的东西:
[7.14923891e-07 7.14923891e-07 ... 8.26478813e-01 8.85589634e-01]
但是,在以下情况下:
tandy = c1.IntegrateColony(3)
ylast = copy.deepcopy(tandy[-1][1])
print(ylast)
tandy = c1.IntegrateColony(3)
print(tandy[-1][1])
ylast = copy.deepcopy(tandy[-1][1])
print(ylast)
我得到全零:
[0.00000000e+00 0.00000000e+00 ... 0.00000000e+00 0.00000000e+00]
[ 0. 0. ... 0. 0.]
我应该补充一点,使用更大的系统和不同的参数,显示tandy[k][1](使用print()或仅通过在命令行中调用它)显示所有非常接近零的非零值,即发生这种情况的详细信息与
integrate
中如何处理ytcurrent
有关。但是Python中有各种各样的上下文,其中列表的所有值最终都是相同的——这与预期相反
例如:
In [159]: x
Out[159]: [0, 1, 2]
In [160]: x=[]
In [161]: y=np.array([1,2,3])
In [162]: for i in range(3):
...: y += i
...: x.append(y)
In [163]: x
Out[163]: [array([4, 5, 6]), array([4, 5, 6]), array([4, 5, 6])]
x
的所有元素都具有相同的值-因为它们都是指向相同y
的指针,因此显示其最终值
但是如果在将其添加到列表之前复制y
,我会看到更改
In [164]: x=[]
In [165]: for i in range(3):
...: y += i
...: x.append(y.copy())
In [166]: x
Out[166]: [array([4, 5, 6]), array([5, 6, 7]), array([7, 8, 9])]
In [167]:
这并不能解释为什么
print
语句会更改值。但整个solout
回调机制有点模糊。我想知道在scipy
中是否有关于定义这样一个回调的陷阱的警告?如果您打印所有的sol,行是否会改变,或者是否都一样?您可能必须使用sol.append((tcurrent,ytcurrent.copy())
,以避免始终存储指向积分器状态向量的相同指针。当您知道对象是数组时,不必麻烦使用deepcopy
<代码>x。复制()就足够了。但我觉得坦迪有点滑稽。它不仅仅是一个独立值的列表。当你连续两次打印(tandy[-1][1])时会发生什么?我会试试看,LutzL。谢谢你,LutzL和hpaulj,谢谢你的建议!至少在一些快速测试中,LutzL建议在添加到sol时使用ytcurrent.copy()
,这似乎修复了奇怪的行为。但是,我想知道为什么只调用tandy
或print(tandy)
vscopy.deepcopy(tandy)
或numpy.copy(tandy)
会影响它所指向的值。谢谢hpaulj。我找不到任何关于solout
陷阱的讨论。你描述的案例很熟悉(尽管我仍然经常被它绊倒!),但似乎无法解释我看到的行为。另外,只需调用tandy[-1][1]
(例如,在控制台中)与numpy.copy()
)不同copy.deepcopy(somearray)
和numpy.copy(somearray)
都调用numpy的array(somearray)
,但我无法进一步跟踪numpy迷宫。。。也许array(somearray)
以另一种方式调用值?如果您给我们一个完整的复制粘贴示例,我可以自己运行它并检查tandy
对象。我也会尝试一些变体,比如只存储当前值的变体,或者在每次迭代时打印一个值的变体。感谢您查看。在每个solout
调用中,ytcurrent
都有一个新的id
,但它共享数据缓冲区(以及yfinal
)。它们都是同一事物的视图。因此,如果您希望每次迭代都使用ytcurrent
值(而不仅仅是最后一次迭代),则必须使用copy
insolout
。我还没有弄清楚为什么“未受保护”的打印会重置这些值。我已经得出结论,这种重置是由内部numpy错误引起的;这与代码中的误用无关。我想我们可以搜索或提交错误报告。但无论它是否已修复,在solout
中的copy()
都是正确的用法。
[(0.0, array([ 0., ... 0.])), ...
(3.0, array([ 0., ... 0.]))]
tandy = c1.IntegrateColony(3); ylast=copy.deepcopy(tandy)
[7.14923891e-07 7.14923891e-07 ... 8.26478813e-01 8.85589634e-01]
import numpy as np
from scipy.integrate import ode
def testODEint(tmax=1):
C0 = np.ones((3,))
# C0 = 1 # This seems to behave the same
def dCdt_simpleinputs(t, C):
return C
y = ode(dCdt_simpleinputs)
y.set_integrator('dopri5')
sol = []
def solout(tcurrent, ytcurrent):
sol.append((tcurrent, ytcurrent)) # Behaves oddly
# sol.append((tcurrent, ytcurrent.copy())) # LutzL's idea: Works
y.set_solout(solout)
y.set_initial_value(y=C0, t=0)
yfinal = y.integrate(tmax)
return sol
tandy = testODEint(1)
ylast = np.copy(tandy[-1][1])
print(ylast) # Expect same values as tandy[-1][1] below
tandy = testODEint(1)
tandy[-1][1]
print(tandy[-1][1]) # Expect same values as ylast above
[ 2.71828196 2.71828196 2.71828196]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00]
In [159]: x
Out[159]: [0, 1, 2]
In [160]: x=[]
In [161]: y=np.array([1,2,3])
In [162]: for i in range(3):
...: y += i
...: x.append(y)
In [163]: x
Out[163]: [array([4, 5, 6]), array([4, 5, 6]), array([4, 5, 6])]
In [164]: x=[]
In [165]: for i in range(3):
...: y += i
...: x.append(y.copy())
In [166]: x
Out[166]: [array([4, 5, 6]), array([5, 6, 7]), array([7, 8, 9])]
In [167]: