2014-09-04 2 views
3
import numpy as np 
bc = np.arange(10) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

# regular way using NumPy function 
np.diff(bc) # array([1, 1, 1, 1, 1, 1, 1, 1, 1]) 

# something similar with array subtraction: 
bc[1:] - bc[:-1] # array([1, 1, 1, 1, 1, 1, 1, 1, 1]) 

# but this does the wrong thing: 
bc[1:] -= bc[:-1] # array([0, 1, 1, 2, 2, 3, 3, 4, 4, 5]) 

В C и C++ программист, я могу понять, почему это происходит (это тетсру() вместо memmove() снова и снова), но похоже, конечных пользователей Python и NumPy может и не ожидать этого. И я не нашел никакой документации, говорящей, что это не сработает.NumPy: Ошибочный результат при изменении массива, используя себя

Вопрос: есть ли здесь ошибка в NumPy (возможно, нет), или есть какая-то документация NumPy, объясняющая, что такое правила в таких ситуациях, или это отсутствует в документации?

Во-вторых, я хотел бы выяснить безопасное рабочее решение, которое является квазиоптимальным в пространстве и времени. То есть, он не должен выделять память за пределы постоянной величины, и это не должно быть глупым чипом pure-Python for for. :) Таковы цели, которые можно надеяться достичь с помощью модификации на месте, которая явно не работает.

Я использую NumPy 1.8.0.

+0

Внутренне 'diff' использует ту же самую разницу среза. Ломтики не используют лишнюю память. Для вывода используется только добавленная память. Поскольку выход имеет размер, отличный от ввода, я не вижу необходимости в различии на месте (особенно, если шаг diff больше 1). – hpaulj

+1

'np.subtract (bc [1:], bc [: - 1], out = bc [: - 1])' производит '[1, 1, 1, 1, 1, 1, 1, 1, 1, 9] '- желаемая разница, за исключением того, что неизменный термин находится в конце. – hpaulj

ответ

0

После обсуждения этого вопроса я нашел какое-то обсуждение. Важным термином для поиска является «срез». Он находится здесь: http://numpy-discussion.10968.n7.nabble.com/Strange-behavior-in-setting-masked-array-values-in-Numpy-1-1-0-td11999.html

На этой странице обсуждается попытка обнаружить и предупредить об этом, но это звучит как потерянная причина. Поэтому я решил найти другой метод на месте, чтобы делать то, что хотел. Вот!

bc[-1:0:-1] -= bc[-2::-1] 

Кредит @fredtantini для явного выписывания чистого Python «для» цикла, который NumPy эффективно делает. Это заставило меня задуматься о том, как исправить это в чистом Python (итерация назад!), Что привело к решению выше.

+3

Серьезно, прежде чем вы сделаете такой опасный трюк ... версия non-inplace, которая возвращает новый массив, так же быстро, так как распределение массива не так уж плохо, и оно работает лучше. – seberg

+0

Я не думаю, что этот метод опасен. Вы? Если да, то что может пойти не так? Во всяком случае, выделение нового массива - это обычный путь наименьшего сопротивления, но если массив имеет размер в несколько гигабайт, он не будет работать. :) –

+0

Это может быть опасно, если разработчики numpy изменят способ повторения массива. Например, большинство «memcpy» реализаций «копируются вперед», но от них не требуется, что они это делают. Определяет ли спецификация numpy порядок итераций? –

0

Я не думаю, что это ошибка:
Выполнение bc[1:] -= bc[:-1] Вы изменяете список при выполнении операций.

Процесс подобен

for i in range(1,len(bc)): 
    bc[i] = bc[i] - bc[i-1] 

Так что следующий шаг bc[i-1] модифицируется:

"i"  1 
bc[1:]: 1,2,3,4,5,… 
bc[:-1]: 0,1,2,3,4,5,… 
bc[1]= 1 - 0 = 1 
new bc: 0,1,2,3,4,5,… 

"i"  2 
bc[1:]: 1,2,3,4,5,… 
bc[:-1]: 0,1,2,3,4,5,… 
bc[2]= 2 - 1 = 1 
new bc: 0,1,1,3,4,5,… 


"i"   3 
bc[1:]: 1,1,3,4,5,… 
bc[:-1]: 0,1,1,3,4,5,… 
bc[1]= 3 - 1 = 2 
new bc: 0,1,1,2,4,5,… 


"i"   4 
bc[1:]: 1,1,2,4,5,… 
bc[:-1]: 0,1,1,2,4,5,… 
bc[1]= 4 - 2 = 2 
new bc: 0,1,1,2,2,5,… 

И так далее так далее.

Для остальной части вопроса я не могу ответить.

+0

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

1

Im, отправляющ здесь снова для того чтобы исправить мой ответ. возможно попробовать:

bc-=np.roll(bc , 1) 

#array([-9, 1, 1, 1, 1, 1, 1, 1, 1, 1]) 
#this arrays length is 10 

#and then for an array with length 9 
bc=bc[ 1 : ] 

#array([1, 1, 1, 1, 1, 1, 1, 1, 1]) 

жаль мисс понимаемый вопрос перед тем,

причина результата:

'array([0, 1, 1, 2, 2, 3, 3, 4, 4, 5])' 

является

, что это действие фактически syntaxed как вычет от

let (say...) a=array([0,1,2,3,4,5,6,7,8,9]) 
updated a <- will be formed as [0, 1-0=1,2-1=1,3-1=2,4-2=2,5-2=3,6-3=3,7-3=4,8-4=4,9-4=5] 

Я думаю, что вы действительно хотите выше

Того EdChum

Смежные вопросы