2016-11-13 23 views
1

我有一个问题,其中,在复制它与copy.deepcopy或numpy.copy后,Numpy数组中的值发生更改,实际上,如果我在复制之前先打印数组,它会得到不同的值。为什么deepcopy更改numpy数组的值?

我使用Python 3.5,numpy的1.11.1,SciPy的0.18.0

我的出发阵列包含在一个元组列表;每个元组是对:一个浮子(时间点)和numpy的阵列(一个ODE中的该时间点的溶液),例如:

[(0.0, array([ 0., ... 0.])), ... 
(3.0, array([ 0., ... 0.]))] 

在这种情况下,我想在最后时间点的阵列。

当我拨打以下:

tandy = c1.IntegrateColony(3) 
ylast = copy.deepcopy(tandy[-1][1]) 
print(ylast) 

我得到的东西,是对这个系统我试图模拟:

[7.14923891e-07 7.14923891e-07 ... 8.26478813e-01 8.85589634e-01] 

然而,有以下:

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()或只是通过在命令行中调用它)显示所有非零值接近零,即< 1e-70,但这对系统仍然不明智。

随着:

tandy = c1.IntegrateColony(3) 
ylast = np.copy(tandy[-1][1]) 
print(ylast) 

我再次得到合理的输出:

[7.14923891e-07 7.14923891e-07 ... 8.26478813e-01 8.85589634e-01] 

其使用scipy.integrate.ode产生 '坦迪' 是以下的(编辑为清楚起见)的功能,和set_solout方法来获得中间时间点的解决方案:

def IntegrateColony(self, tmax=1): 
    # I edited out initialization of dCdt & first_step for clarity. 
    y = ode(dCdt) 
    y.set_integrator('dopri5', first_step=dt0, nsteps=2000) 
    sol = [] 
    def solout(tcurrent, ytcurrent): 
     sol.append((tcurrent, ytcurrent)) 

    y.set_solout(solout) 
    y.set_initial_value(y=C0, t=0) 
    yfinal = y.integrate(tmax) 

    return sol 

尽管I co通过返回yfinal得到最后一个时间点,我想弄清楚为什么它的行为是这样的。

感谢您的建议!

米奇


编辑: 如果我打印所有溶胶(print(tandy)print(IntegrateColony...)的,它出来作为(在数组作为0与值)如上所示,即:

[(0.0, array([ 0., ... 0.])), ... 
(3.0, array([ 0., ... 0.]))] 

但是,如果将其复制为(y = copy.deepcopy(tandy); print(y)),则阵列的值介于1e-7和1e + 1之间。

如果我连续两次执行print(tandy[-1][1]),它们将填充零,但格式更改(从0.00000.)。

我在遵循LutzL和hpaulj的评论中的建议时注意到了另外一个特性:如果我在控制台(运行Spyder)中运行tandy = c1.IntegrateColony(3),则数组在变量浏览器中填充为零。但是,如果我运行在控制台以下:

tandy = c1.IntegrateColony(3); ylast=copy.deepcopy(tandy) 

无论在坦迪和ylast阵列在我希望的范围内都充满了价值观,print(tandy[-1][1])现在给:

[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 

当我运行它,我得到以下输出ylasttandy[-1][1]

[ 2.71828196 2.71828196 2.71828196] 
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00] 

代码当我遇到这个问题时,我一直在努力工作是一个令人尴尬的混乱,但如果你想看看,旧版本在这里:https://github.com/mvondassow/BryozoanModel2

+2

如果你打印所有的sol,行是否改变或者都是一样的?您可能必须使用'sol.append((tcurrent,ytcurrent.copy()))'来避免始终存储与积分器状态向量相同的指针。 – LutzL

+1

当你知道对象是一个数组时,不要打扰'deepcopy'。 'x.copy()'就足够了。但我觉得'tandy'有一些有趣的东西。这不仅仅是一个独立价值清单。当你连续两次打印(tandy [-1] [1])时会发生什么? – hpaulj

+0

我会试试LutzL。 –

回答

1

为什么发生这种情况的详细信息与在integrate中的处理方式有关。但是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中是否存在关于定义这种回调的陷阱的警告?

+0

谢谢hpaulj。我找不到任何关于'solout'的陷阱。你描述的情况是很熟悉的(尽管我经常会被它绊倒!),但似乎没有解释我看到的行为。此外,只需调用'tandy [-1] [1]'(例如在控制台中),它与'numpy.copy()'不同)。 'copy.deepcopy(somearray)'&'numpy.copy(somearray)'都会调用numpy的''array(somearray)',但我失去了进一步追踪numpy迷宫......也许'array(somearray)'调用不同的值办法? –

+0

如果你给我们一个完整的复制粘贴示例,我可以运行它并自己检查'tandy'对象。我也会尝试各种变体,例如只存储当前值的变体,或者在每次迭代时打印一个值的变体。 – hpaulj

+0

我在原来的问题中添加了一个简单的例子,它可以完成我一直在运行的任务。谢谢参观。 –

相关问题