Полезен ли флаг массива OWNDATA? - PullRequest
0 голосов
/ 12 марта 2020

Один из флагов NumPy массива равен OWNDATA, который описывается в документации:

OWNDATA (O)
Массив владеет памятью, которую он использует, или заимствует ее у другого объекта.

Мне было интересно, есть ли вообще какое-либо использование для этого флага, по крайней мере, как часть информации в API publi c , Есть некоторые вопросы, касающиеся упоминания этих флагов, например Как я могу определить, создает ли NumPy представление или копию? или Numpy изменить вид , что говорит о том, что OWNDATA обычно не следует использовать для определения, является ли массив копией или представлением. Но я не нашел случаев, когда значение флага действительно полезно.

Я думал об этом на примере, подобном этому:

import numpy as np
a = np.tile([1], 3)
print(a)
# [1 1 1]
print(a.flags)
#   C_CONTIGUOUS : True
#   F_CONTIGUOUS : True
#   OWNDATA : False
#   WRITEABLE : True
#   ALIGNED : True
#   WRITEBACKIFCOPY : False
#   UPDATEIFCOPY : False

np.tile возвращает новый непрерывный массив, содержащий мозаичный ввод. В этом примере a действительно является смежным, но OWNDATA - это False. Оказывается, причина в том, что в конце np.tile происходит изменение формы, поэтому технически данные принадлежат другому массиву, который впоследствии был преобразован в результат функции. Однако у меня нет ссылок на этот массив, и во всех отношениях я должен рассматривать a как владельца его данных. Я представляю, если бы np.tile было реализовано изначально, возможно, OWNDATA было бы True. Однако я не знаю (и не должен знать), какие функции NumPy являются нативными или нет, поэтому мне кажется, что OWNDATA не дает никакой полезной информации конечным пользователям библиотеки. Я не знаком с NumPy управлением памятью, и, вероятно, есть причина иметь эту информацию внутри, но я не очень уверен в том, чтобы иметь ее в качестве (потенциально вводящего в заблуждение) общедоступного флага массива.

Кто-нибудь знает о каком-либо фактическом, практическом использовании флага OWNDATA?

РЕДАКТИРОВАТЬ: Для пояснения, я знаю, что значение OWNDATA не связано с тем, что функция, которая генерирует массив является родной (скомпилированный) или нет. Я имел в виду, что, хотя массив, возвращаемый tf.tile, функционально владеет своими данными (поскольку фактический владелец данных больше не может быть доступен), значение OWNDATA не отражает это, и, возможно, скомпилированная реализация функции, которая не использует промежуточные объекты ndarray, может вернуть массив с OWNDATA, установленным в True. Дело в том, что разные детали реализации могут приводить к разным значениям OWNDATA в других функционально эквивалентных массивах, поэтому неясно, какое значение флага OWNDATA должно представлять пользователь библиотеки или как оно может быть полезно .

1 Ответ

1 голос
/ 12 марта 2020

Я не смотрю на flags почти так же, как __array_interface__ (особенно его ключ data).

Является ли метод / функция 'native' (скомпилированным?), Не имеет ничего общего с OWNDATA.

In [16]: np.arange(12).flags['OWNDATA']                                                        
Out[16]: True
In [17]: np.arange(12).reshape(3,4).flags['OWNDATA']                                           
Out[17]: False
In [18]: np.arange(12).reshape(3,4).copy().flags['OWNDATA']                                    
Out[18]: True

reshape - это быстрый скомпилированный код, но он возвращает view новый массив с собственными shape и strides, но ссылающийся на буфер данных arange. Этот массив 1d arange все еще существует, хотя я никогда не назначал его переменной.

copy создает новый массив со своими собственными данными. Эта копия дороже, чем изменение формы, и обычно не требуется - если только мне не нужно обеспечить полную независимость между массивами.

Мы можем проиллюстрировать последствия (ы) OWNDATA с помощью:

In [19]: x = np.arange(12)                                                                     
In [20]: y = x.reshape(3,4)                                                                    
In [21]: z = y.copy()                                                                          
In [22]: z[0,:] *= 10                                                                          
In [23]: z                                                                                     
Out[23]: 
array([[ 0, 10, 20, 30],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
In [24]: x                  # no change                                                                                     
Out[24]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
In [25]: y[0,:] *= 10                                                                          
In [26]: y                                                                                     
Out[26]: 
array([[ 0, 10, 20, 30],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
In [27]: x                 # changing y changed x                                                                    
Out[27]: array([ 0, 10, 20, 30,  4,  5,  6,  7,  8,  9, 10, 11])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...