2016-11-13 9 views
1

У меня возникла проблема, при которой значения в массиве Numpy изменяются после копирования с помощью copy.deepcopy или numpy.copy. Фактически, я получаю разные значения, если я просто напечатаю массив перед его копированием.Почему значение глубины изменения значения numpy массива?

Я использую Python 3.5, Numpy 1.11.1, 0.18.0 SciPy

Мой исходный массив содержится в списке кортежей; каждый кортеж пара: поплавок (время точка) и массив NumPy (решение ОДЫ в этот момент времени), например:

[(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 

Хотя я сотрудничаю uld получить последнюю точку времени, вернув yfinal, я бы хотел получить все время курса, как только я выясню, почему он ведет себя так, как есть.

Спасибо за ваши предложения!

Микки


Edit: Если я печатаю все золе (print(tandy) или print(IntegrateColony...), то выходит, как показано выше (со значениями в массивах, как 0), то есть:

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

Однако, если я скопирую его (y = copy.deepcopy(tandy); print(y)), массивы берут значения между 1е-7 и 1е + 1.

Если я делаю print(tandy[-1][1]) два раза подряд, они заполняются нулями, но формат изменяется (от 0.0000 до 0.).

Еще одна особенность, которую я заметил при выполнении предложений в комментариях LutzL и hpaulj: если я запустил tandy = c1.IntegrateColony(3) в консоли (работает Spyder), массивы заполняются нулями в проводнике переменных. Тем не менее, если я запускаю следующее в консоли:

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] 

Даже если я найду решение, которое остановит это поведение, я буду признателен за чье-либо понимание того, что происходит, поэтому я не повторю те же ошибки.

Спасибо!


Edit: Вот простой пример, который дает такое поведение:

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 

Когда я запускаю это, я получаю следующий результат для ylast и tandy[-1][1]:

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

Код Я работал над тем, когда я столкнулся с этой проблемой, это смущающий беспорядок, но если вы хотите взглянуть, здесь находится старая версия: https://github.com/mvondassow/BryozoanModel2

+2

Если вы печатаете весь зонд, измените ли строки или все равно? Возможно, вам придется использовать 'sol.append ((tcurrent, ytcurrent.copy()))', чтобы избежать сохранения всегда одного и того же указателя на вектор состояния интегратора. – LutzL

+1

Не утруждайте себя 'deepcopy', когда вы знаете, что объект является массивом. 'x.copy()' достаточно. Но я думаю, что есть что-то смешное в отношении «tandy». Это не просто список независимых значений. Что происходит, когда вы выполняете 'print (tandy [-1] [1])' дважды подряд? – hpaulj

+0

Я попробую, LutzL. –

ответ

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 о ловушках при определении такого обратного вызова?

+0

Спасибо, hpaulj. Я не мог найти никакого обсуждения ловушек о 'solout'.Случай, который вы описываете, является знакомым (хотя я все-таки слишком часто спотыкаюсь об этом!), Но, похоже, не объясняет поведение, которое я вижу. Кроме того, просто вызов 'tandy [-1] [1]' (например, в консоли) отличает его от 'numpy.copy()'). 'copy.deepcopy (somearray)' и 'numpy.copy (somearray)' оба вызывают numpy 'array (somearray)', но я потерял отслеживание лабиринта numpy дальше ... Может быть, 'array (somearray)' вызывает значения в другом путь? –

+0

Если вы дадите нам полный экземпляр copy-n-paste, я могу запустить его и сам изучить объект «tandy». Я также хотел бы попробовать варианты, такие как тот, который просто сохраняет текущее значение, или значение, которое печатает значение на каждой итерации. – hpaulj

+0

Я добавил простой пример к моему оригинальному вопросу, который делает то, что я использовал. Спасибо, что посмотрели. –