Различное поведение индексации и нарезки в структурированных массивах numpy

Предположим, у вас есть структурированный массив a:

import numpy as np

a = np.array([1, 2, 3, 4, 5, 6], dtype=[('val', 'i4')])
print(a)
[(1,) (2,) (3,) (4,) (5,) (6,)]

Теперь, если я хочу изменить одну из записей на другое значение, следующие два способа кажутся эквивалентными (Случай I):

# both of these work
"""version a)"""
a['val'][1] = 10
print(a)
[( 1,) (10,) ( 3,) ( 4,) ( 5,) ( 6,)]

"""version b)"""
a[1]['val'] = 2
print(a)
[(1,) (2,) (3,) (4,) (5,) (6,)]

Но эта двусмысленность (не уверен, что это подходящий термин) нарушается, если мы пытаемся изменить более одной записи (Случай II):

"""version a)"""
a['val'][[0, 1]] = 15
print(a)
[(15,) (15,) ( 3,) ( 4,) ( 5,) ( 6,)]
# this works

"""version b)"""
a[[0, 1]]['val'] = 5
print(a)
[(15,) (15,) ( 3,) ( 4,) ( 5,) ( 6,)]
# this has no effect

Я подумал, что, возможно, во втором случае, версия б), создается новый объект, поэтому присвоение нового значения этим записям влияет только на новый объект, но не на исходный. Но также и в первом случае, версии b), создается впечатление, что создается новый объект, так как оба следующих оператора возвращают False:

print(a[1]['val'] is a['val'][1])
print(a['val'][[0, 1]] is a[[0, 1]]['val'])

Тот факт, что эта двусмысленность дается только в первом случае, но не во втором, кажется мне непоследовательным, если, по крайней мере, сбивает с толку. Что мне не хватает?


person mapf    schedule 24.04.2020    source источник
comment
Любая индексация создает новый объект массива, поэтому is не является хорошим тестом. Важно то, производит ли первое индексирование copy или view. a[...][...] = value особенно чувствителен к этому различию.   -  person hpaulj    schedule 24.04.2020
comment
Даже с простым массивом dtype arr[[0,1]][1:] = 1 не изменит arr. arr[[0,1]] — расширенная индексация; arr[0] и arr[3:] являются базовыми, независимо от dtype.   -  person hpaulj    schedule 24.04.2020
comment
Посмотрите только на a['val'], a[1] и a[[0,1]]. Обратите внимание на форму и тип. Индексация полей и записей не взаимозаменяемы. И индексирование полей не является индексированием столбцов.   -  person hpaulj    schedule 24.04.2020
comment
Благодарю вас! Итак, есть ли способ проверить, происходят ли два массива из одного и того же исходного массива (и, кроме того, содержат одинаковые значения)? Я не уверен, есть ли на самом деле прецедент для этого, просто любопытно.   -  person mapf    schedule 27.04.2020


Ответы (1)


Отличное наблюдение. Согласно документу numpy: для всех случаев массивов индексов. , то возвращается копия исходных данных, а не представление, которое получают для срезов. В то время как индексирование одного элемента возвращает представление.

Также обратите внимание, что в соответствии с документом scipy, вызывающие поля в структурированных массивах создают представление, а также индексация с целым числом создает структурированный скаляр, для которого в отличие от других скаляров numpy, структурированные скаляры являются изменяемыми и действуют как представления в исходном массиве, так что изменение скаляра изменит исходный массив. Структурированные скаляры также поддерживают доступ и назначение по имени поля

Хотя он может не разделять память (я не уверен в его внутренней реализации), он действует как представление и изменяет исходный массив. Поэтому, когда вы вызываете свой массив с одним целым числом, он действует как представление и изменяет исходный массив, тогда как когда вы вызываете его массивом с целочисленными индексами, он создает копию и не изменяет исходный массив.

person Ehsan    schedule 24.04.2020
comment
Благодарю вас! Это объясняет поведение, хотя я думаю, что оно все еще очень неинтуитивно и склонно к ошибкам. - person mapf; 27.04.2020