Подтвердить что ты не робот

Есть ли способ проверить, имеют ли массивы 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 имеют одинаковые байты.

4b9b3361

Ответ 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']

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