2015-07-03 1 views
3

Я недавно видел явление в работе со структурированными массивами numpy, что не имеет смысла. Я надеюсь, кто-то может помочь мне понять, что происходит. Я привел минимальный рабочий пример для иллюстрации проблемы. Проблема заключается в следующем:Почему назначение булевского индексированного структурированного массива зависит от упорядочения индекса?

При индексировании структурированную Numpy массив с булевой маской, это работает:

arr['fieldName'][boolMask] += val 

но следующий не будет:

arr[boolMask]['fieldName'] += val 

Вот минимальный рабочий пример:

import numpy as np 

myDtype = np.dtype([('t','<f8'),('p','<f8',(3,)),('v','<f4',(3,))]) 

nominalArray = np.zeros((10,),dtype=myDtype) 
nominalArray['t'] = np.arange(10.) 
# In real life, the other fields would also be populated 
print "original times: {0}".format(nominalArray['t']) 

# Add 10 to all times greater than 5 
timeGreaterThan5 = nominalArray['t'] > 5 
nominalArray['t'][timeGreaterThan5] += 10. 
print "times after first operation: {0}".format(nominalArray['t']) 

# Return those times to their original values 
nominalArray[timeGreaterThan5]['t'] -= 10. 
print "times after second operation: {0}".format(nominalArray['t']) 

Выполнение этого результата дает следующие результаты:

original times: [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] 
times after first operation: [ 0. 1. 2. 3. 4. 5. 16. 17. 18. 19.] 
times after second operation: [ 0. 1. 2. 3. 4. 5. 16. 17. 18. 19.] 

Мы ясно видим здесь, что вторая операция не имела никакого эффекта. Если бы кто-нибудь мог объяснить, почему это происходит, было бы весьма полезно.

+0

не будет ли это 'номинальныйArray [" t "] [timeGreaterThan5] - = 10' –

+0

@PadraicCunningham Это устранит проблему. Мне просто интересно, почему это решение. Что такого особенного в заказе здесь? – tintedFrantic

+3

Теперь я получаю вас, они оба возвращают разные объекты, один - это вид, а другой - нет, я предполагаю, что продвинутый vs нормальный индекс, 'initialArray [timeGreaterThan5]' возвращает '[(16.0, [0.0, 0.0, 0.0], [ 0.0, 0.0, 0.0]) ... 'поэтому срез, возвращаемый с' номинальныйArray [timeGreaterThan5] ', не является объектом вида –

ответ

3

Это действительно проблема копирования v view. Но я расскажу подробнее.

Ключевое различие между представлением v в копии - это шаблон индексации, регулярный или нет. Регулярный может быть выражен через массив shape, strides и dtype. В общем случае логический индекс (и связанный список индексов) не может быть выражен в этих терминах, поэтому numpy должен вернуть копию.

Мне нравится смотреть на недвижимость arr.__array_interface__. Он показывает форму, шаги и указатель на буфер данных. Если указатель совпадает с указателем, это view.

С arr[idx] += 1, индексирование фактически является методом setitem, который выбирает, какие элементы буфера данных должны быть изменены с добавлением. Различие между представлением и копией не применяется.

Но с arr[idx1][idx2] += 1, первая индексация - это метод getitem. Для этого важно различие между взглядом и копией. Второе индексирование изменяет массив, созданный 1-м. Если это представление, изменение влияет на исходные данные; если копия, ничего не происходит. Копия может быть изменена, но она исчезает по экрану сборки мусора.

С 2d массивами вы можете комбинировать эти 2 этапа индексирования, arr[idx1, idx2] += 1; и на самом деле это предпочтительный синтаксис.

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

Простой структурированный массив:

In [234]: arr=np.ones((5,),dtype='i,f,i,f') 
In [235]: arr.__array_interface__ 
{'strides': None, 
'shape': (5,), 
'data': (152524816, False), 
'descr': [('f0', '<i4'), ('f1', '<f4'), ('f2', '<i4'), ('f3', '<f4')], 
'typestr': '|V16', 
'version': 3} 

Выбор одного поля производит вид - такой же указатель данных

In [236]: arr['f0'].__array_interface__['data'] 
Out[236]: (152524816, False) 

Выбор элементов булевой производит копию (указатель дифф)

In [242]: idx = np.array([1,0,0,1,1],bool) 
In [243]: arr[idx].__array_interface__['data'] 
Out[243]: (152629520, False) 

So arr['f0'][idx] += 1 изменяет выбранные элементы из f0.

arr[idx]['f0'] += 1 изменяет поле формы f0, без воздействия на arr.

arr[idx]['f0'] + 1 и arr['f0'][idx] + 1 отображаются одинаково, но они не пытаются выполнять какие-либо изменения на месте.

Вы можете выбрать несколько полей из структурированного массива, arr[['f0','f2']]. Но это копия. (и я получаю предупреждение о том, что я делаю явное копирование).

+0

Отличный ответ, спасибо. –