Numpy remodelar en vista

Estoy confundido acerca de los resultados de la remodelación numpy operada en una vista. En el siguiente q.flags muestra que no es el propietario de los datos, pero q.base no es ni x ni y, entonces, ¿qué es? Me sorprende ver que q.strides es 8, lo que significa que recibe el siguiente elemento cada vez que mueve 8 bytes en la memoria (si lo comprendo correctamente). Sin embargo, si ninguna de las matrices que no sea x posee datos, el único búfer de datos es de x, lo que no permite obtener el siguiente elemento de q moviendo 8 bytes.

In [99]: x = np.random.rand(4, 4) In [100]: y = xT In [101]: q = y.reshape(16) In [102]: q.base is y Out[102]: False In [103]: q.base is x Out[103]: False In [104]: y.flags Out[104]: C_CONTIGUOUS : False F_CONTIGUOUS : True OWNDATA : False WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False In [105]: q.flags Out[105]: C_CONTIGUOUS : True F_CONTIGUOUS : True OWNDATA : False WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False In [106]: q.strides Out[106]: (8,) In [107]: x Out[107]: array([[ 0.62529694, 0.20813211, 0.73932923, 0.43183722], [ 0.09755023, 0.67082005, 0.78412615, 0.40307291], [ 0.2138691 , 0.35191283, 0.57455781, 0.2449898 ], [ 0.36476299, 0.36590522, 0.24371933, 0.24837697]]) In [108]: q Out[108]: array([ 0.62529694, 0.09755023, 0.2138691 , 0.36476299, 0.20813211, 0.67082005, 0.35191283, 0.36590522, 0.73932923, 0.78412615, 0.57455781, 0.24371933, 0.43183722, 0.40307291, 0.2449898 , 0.24837697]) 

ACTUALIZAR:

Resulta que esta pregunta ha sido formulada en el foro de discusión de números: http://numpy-discussion.10968.n7.nabble.com/OWNDATA-flag-and-reshape-views-vs-copies-td10363.html

En resumen: no siempre puede confiar en ndarray.flags['OWNDATA'] .

 >>> import numpy as np >>> x = np.random.rand(2,2) >>> y = xT >>> q = y.reshape(4) >>> y[0,0] 0.86751629121019136 >>> y[0,0] = 1 >>> q array([ 0.86751629, 0.87671107, 0.65239976, 0.41761267]) >>> x array([[ 1. , 0.65239976], [ 0.87671107, 0.41761267]]) >>> y array([[ 1. , 0.87671107], [ 0.65239976, 0.41761267]]) >>> y.flags['OWNDATA'] False >>> x.flags['OWNDATA'] True >>> q.flags['OWNDATA'] False >>> np.may_share_memory(x,y) True >>> np.may_share_memory(x,q) False 

Debido a que q no reflejó el cambio en el primer elemento, como x o y , de alguna manera debe ser el propietario de los datos (de alguna manera se explica a continuación).

Hay más discusión sobre la OWNDATA en la lista de correo numpy-Discussion . En la sección ¿Cómo puedo saber si NumPy crea una vista o una copia? En cuanto a la pregunta, se menciona brevemente que a veces parece fallar la simple verificación de los flags.owndata de la flags.owndata de un ndarray y que no parece confiable, como usted menciona. Eso es porque cada ndarray también tiene un atributo base :

la base de un ndarray es una referencia a otra matriz si la memoria se originó en otro lugar (de lo contrario, la base es None ). La operación y.reshape(4) crea una copia, no una vista, porque los pasos de y son (8,16) . Para cambiarlo de forma (C-contiguo) a (4,) , el puntero de la memoria tendría que saltar 0->16->8->24 , lo que no es posible con un solo paso. Por q.base tanto, q.base apunta a la ubicación de memoria generada por la operación de copia forzada y.reshape , que tiene la misma forma que y , pero copió los elementos y, por lo tanto, vuelve a tener pasos normales: (16, 8) . q.base no está vinculado por ningún otro nombre, ya que fue el resultado de la operación de copia forzada y.reshape(4) . Solo ahora se puede ver el objeto q.base en una forma (4,) , porque las zancadas lo permiten. q es entonces una vista de q.base .

Para la mayoría de las personas, sería confuso ver que q.flags.owndata es False , porque, como se muestra arriba, no es una vista de y . Sin embargo, es una vista en una copia de y . Sin q.base , esa copia, q.base , es el propietario de los datos. Por lo tanto, las banderas son realmente correctas, si inspeccionas de cerca.

Me gusta usar .__array_interface__ .

 In [811]: x.__array_interface__ Out[811]: {'data': (149194496, False), 'descr': [('', ' 

La transposición se realizó invirtiendo los pasos. El puntero de datos base es el mismo.

 In [817]: q.__array_interface__ Out[817]: {'data': (165219304, False), 'descr': [('', ' 

Entonces los datos q son una copia (puntero diferente). Avances (8,) significa que se puede acceder a sus elementos pasando de un f8 al siguiente. Pero un x.reshape(16) es una vista de x , porque se puede acceder a sus datos con un simple paso de 8 .

Para acceder a los datos originales en el orden q , tendría que pasar 32 bytes 3 veces (abajo x filas), luego volver al inicio y al paso 8 a la 2ª columna x , seguidos de 3 pasos de fila, etc. No funciona de esta manera, tiene que trabajar desde una copia.

Tenga en cuenta también que y[0,0] cambia x[0,0] , pero q[0] es independiente de ambos.

Mientras OWNDATA para q es falso, es verdadero para y.ravel() y y.flatten() . Sospecho que, en este caso, reshape() está haciendo una copia y luego remodelando, y es la copia intermedia la que "posee" los datos, q.base .