Pregunta ¿Hay alguna manera de comprobar si las matrices NumPy comparten los mismos datos?


Mi impresión es que en NumPy, dos matrices pueden compartir la misma memoria. Toma el siguiente ejemplo:

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

Entonces claramente b no hizo una copia de a; simplemente creó algunos metadatos nuevos y los adjuntó al mismo búfer de memoria que a esta usando. ¿Hay alguna manera de verificar si dos matrices hacen referencia al mismo buffer de memoria?

Mi primera impresión fue usar a.data is b.data, pero eso devuelve falso. puedo hacer a.data == b.data que devuelve True, pero no creo que eso compruebe para asegurarse a y b compartir el mismo buffer de memoria, solo que el bloque de memoria referenciado por a y el referido por b tener los mismos bytes


32
2017-07-02 01:09


origen


Respuestas:


Creo que la respuesta de jterrace es probablemente la mejor manera de hacerlo, pero aquí hay otra posibilidad.

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

Ejemplo:

>>> 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

Aquí hay un diagrama que muestra el tiempo para cada share_memory(a,a[::2]) llamada en función del número de elementos en a en mi computadora.

share_memory function


8
2017-07-02 03:16



Puedes usar el base atributo para verificar si una matriz comparte la memoria con otra matriz:

>>> import numpy as np
>>> a = np.arange(27)
>>> b = a.reshape((3,3,3))
>>> b.base is a
True
>>> a.base is b
False

No estoy seguro si eso resuelve tu problema. El atributo base será None si la matriz posee su propia memoria. Tenga en cuenta que la base de una matriz será otra matriz, incluso si es un subconjunto:

>>> c = a[2:]
>>> c.base is a
True

26
2017-07-02 01:30



Solo haz:

a = np.arange(27)
a.__array_interface__['data']

La segunda línea devolverá una tupla donde la primera entrada es la dirección de la memoria y la segunda es si la matriz es de solo lectura. Combinado con la forma y el tipo de datos, puede calcular el espacio exacto de la dirección de memoria que abarca la matriz, de modo que también puede resolverlo cuando una matriz es un subconjunto de otra.


4
2018-03-10 14:58