Есть ли способ проверить, имеют ли массивы NumPy одни и те же данные?
Мое впечатление, что в NumPy два массива могут использовать одну и ту же память. Возьмем следующий пример:
import numpy as np
a=np.arange(27)
b=a.reshape((3,3,3))
a[0]=5000
print (b[0,0,0]) #5000
#Some tests:
a.data is b.data #False
a.data == b.data #True
c=np.arange(27)
c[0]=5000
a.data == c.data #True ( Same data, not same memory storage ), False positive
Значит, b
не сделал копию a
; он просто создал некоторые новые метаданные и привязал их к тому же буферу памяти, который использует a
. Есть ли способ проверить, ссылаются ли на два массива один и тот же буфер памяти?
Мое первое впечатление заключалось в использовании a.data is b.data
, но это возвращает false. Я могу сделать a.data == b.data
, который возвращает True, но я не думаю, что проверки, чтобы убедиться, что a
и b
используют один и тот же буфер памяти, только тот блок памяти, на который ссылается a
, и тот, на который ссылается b
имеют одинаковые байты.
Ответы
Ответ 1
Я думаю, что ответ jterrace, вероятно, лучший способ пойти, но вот еще одна возможность.
def byte_offset(a):
"""Returns a 1-d array of the byte offset of every element in `a`.
Note that these will not in general be in order."""
stride_offset = np.ix_(*map(range,a.shape))
element_offset = sum(i*s for i, s in zip(stride_offset,a.strides))
element_offset = np.asarray(element_offset).ravel()
return np.concatenate([element_offset + x for x in range(a.itemsize)])
def share_memory(a, b):
"""Returns the number of shared bytes between arrays `a` and `b`."""
a_low, a_high = np.byte_bounds(a)
b_low, b_high = np.byte_bounds(b)
beg, end = max(a_low,b_low), min(a_high,b_high)
if end - beg > 0:
# memory overlaps
amem = a_low + byte_offset(a)
bmem = b_low + byte_offset(b)
return np.intersect1d(amem,bmem).size
else:
return 0
Пример:
>>> a = np.arange(10)
>>> b = a.reshape((5,2))
>>> c = a[::2]
>>> d = a[1::2]
>>> e = a[0:1]
>>> f = a[0:1]
>>> f = f.reshape(())
>>> share_memory(a,b)
80
>>> share_memory(a,c)
40
>>> share_memory(a,d)
40
>>> share_memory(c,d)
0
>>> share_memory(a,e)
8
>>> share_memory(a,f)
8
Вот график, показывающий время для каждого вызова share_memory(a,a[::2])
как функцию количества элементов в a
на моем компьютере.
![share_memory function]()
Ответ 2
Вы можете использовать атрибут base, чтобы проверить, разделяет ли массив память с другим массивом:
>>> import numpy as np
>>> a = np.arange(27)
>>> b = a.reshape((3,3,3))
>>> b.base is a
True
>>> a.base is b
False
Не уверен, что это решает вашу проблему. Базовый атрибут будет None
, если массив владеет собственной памятью. Обратите внимание, что базой массива будет другой массив, даже если он является подмножеством:
>>> c = a[2:]
>>> c.base is a
True
Ответ 3
Просто выполните:
a = np.arange(27)
a.__array_interface__['data']
Вторая строка вернет кортеж, где первая запись - адрес памяти, а вторая - только чтение массива. В сочетании с формой и типом данных вы можете определить точный интервал адреса памяти, который охватывает массив, поэтому вы также можете решить эту проблему, когда один массив является подмножеством другого.