为什么deepcopy会更改numpy数组的值?

时间:2016-11-13 20:27:44

标签: arrays numpy scipy copy ode

我遇到的问题是,在使用copy.deepcopy或numpy.copy复制Numpy数组后,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]

生成' tandy'是以下(为清晰起见编辑),它使用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

虽然我可以通过返回yfinal得到最后一个时间点,但是我想知道为什么它的行为方式就是全部时间。

感谢您的建议!

米奇

编辑: 如果我打印所有sol(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评论中的建议时注意到的另一个功能是:如果我在控制台中运行tandy = c1.IntegrateColony(3)(运行Spyder),则数组中的零填充为零变量探险家。但是,如果我在控制台中运行以下命令:

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

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

1 个答案:

答案 0 :(得分:1)

发生这种情况的详细信息与ytcurrent中处理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回调机制有点模糊。我想知道import React from 'react'; import { MuiThemeProvider} from 'material-ui'; import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui'; // properties of TableHeader component let headerProps = { enableSelectAll: false, displaySelectAll: false, adjustForCheckbox: false }; // initial set of rows, simulating data from the database let rows = [ {firstName: "Adrian", favColor: "gold", uniqueId: 0 }, {firstName: "Alma", favColor: "green", uniqueId: 1 }, {firstName: "Conny", favColor: "black", uniqueId: 2 }, {firstName: "Jane", favColor: "blue", uniqueId: 3 } ]; // our table hader information, key is the name of the // property to sort by when the header is clicked let headers = [ {name: "First Name", key: "firstName"}, {name: "Favorite Color", key: "favColor"} ]; // our table component that can sort columns class SortableTable extends React.Component { constructor(props){ super(props); this.state = {rows, sortBy: 'firstName'}; } renderHeaders(){ let header= headers.map( (h) => { return <SortableHeader key={h.key} name={h.name} onClicked={()=>this.updateSortBy(h.key)} isSortColumn={this.state.sortBy == h.key}/> }); return <TableRow>{header}</TableRow>; } renderRows() { return this.state.rows.map( (row, i) => <UserRow {...row} key={row.uniqueId}/> ); } updateSortBy(sortBy){ // multiple clicks on the same column reverse the sort order if( sortBy == this.state.sortBy ){ this.setState( {rows: [...this.state.rows.reverse()]} ); return; } let rows = [...this.state.rows]; rows.sort( (a,b) => { if (a[sortBy] < b[sortBy]) return -1; if(a[sortBy] > b[sortBy]) return 1; return 0; }); this.setState({rows, sortBy}); } render() { return ( <MuiThemeProvider> <Table> <TableHeader {...headerProps}> {this.renderHeaders()} </TableHeader> <TableBody> {this.renderRows()} </TableBody> </Table> </MuiThemeProvider> ); } } function SortableHeader(props){ let style = { cursor: "pointer" } if(props.isSortColumn){ style.fontWeight = "bold"; style.color = "black"; } return ( <TableHeaderColumn> <div style={style} onClick={() => props.onClicked()}>{props.name}</div> </TableHeaderColumn> ); } function UserRow(props){ return ( <TableRow> <TableRowColumn>{props.firstName}</TableRowColumn> <TableRowColumn>{props.favColor}</TableRowColumn> </TableRow> ); } export default SortableTable;中是否有关于定义此类回调的陷阱的警告?