2015-08-22 3 views
1

J'essaie d'obtenir une vue de 2D ndarray comme un enregistrement ou un tableau structuré sans copier. Cela semble fonctionner très bien si a est propriétaire des donnéesObtenez une vue de recarray d'un ndarray (qui peut également être une vue)

>>> a = np.array([[ 1, 391, 14, 26], 
       [ 17, 371, 15, 30], 
       [641, 340, 4, 7]]) 
>>> b = a.view(zip('abcd',[a.dtype]*4)) 
array([[(1, 391, 14, 26)], 
     [(17, 371, 15, 30)], 
     [(641, 340, 4, 7)]], 
     dtype=[('a', '<i8'), ('b', '<i8'), ('c', '<i8'), ('d', '<i8')]) 
>>> b.base is a 
True 

Mais si a est déjà vue, cela ne fonctionne pas. Voici un exemple

>>> b = a[:,[0,2,1,3]] 
>>> b.base is None 
False 
>>> b.view(zip('abcd',[a.dtype]*4)) 
ValueError: new type not compatible with array. 

Fait intéressant, dans ce cas b.base est une transposition de la vue

>>> (b.base == b.T).all() 
True 

Il est donc logique que numpy ne pouvait pas créer la vue de ce que je voulais.

Cependant, si j'utilise

>>> b = np.take(a,[0,2,1,3],axis=1) 

Il en résulte b être une copie correcte des données afin de prendre les travaux de vue recarray. Question secondaire: Quelqu'un peut-il expliquer ce comportement par opposition à l'indexation?

Ma question est, est-ce que je vais à ce sujet dans le mauvais sens? Est-ce que prendre une vue comme je le fais n'est pas supporté? Si oui, quelle serait la bonne façon de le faire?

Répondre

1

(grand modifier) ​​

b est F_CONTINGUOUS (voir b.flags). Le nombre de champs dans la vue doit alors correspondre au nombre de lignes de b, et non le nombre de colonnes:

In [204]: b=a[:,[0,2,1,3]].view('i4,i4,i4') 
In [205]: b 
Out[205]: 
array([[(0, 4, 8), (2, 6, 10), (1, 5, 9), (3, 7, 11)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')]) 

Un cas plus simple est a.copy(order='F').view('i4,i4,i4')

np.take(a,[0,2,1,3],axis=1) et a[:,[0,2,1,3]].copy() produire des copies C_CONTIGUOUS, et donc le peuvent être vu avec 4 champs.

Notez également le b.base a 3 colonnes.


(trébuchant plus tôt autour de la question)

Être vue est pas un problème.

a = np.arange(12).reshape(3,4) 
a.view('i4,i4,i4,i4') 

fait très bien.

Faire une copie de la première b fonctionne également:

b=a[:,[0,2,1,3]].copy() 
b.view('i4,i4,i4,i4') 

Le 1er b (sans copie) est F_CONTIGUOUS (voir b.flags). C'est ce que votre b.base == b.T montre.

np.take produit le même genre de tableau que celui bcopy - à savoir mêmes drapeaux et même écran __array_interface__.

Autres choses qui fonctionnent:

a[[0,2,1],:].view('i4,i4,i4,i4') 
a.T[[0,2,1,3],:].T.view('i4,i4,i4,i4') 

Si je remplace le découpage mixte et l'indexation tableau avec l'indexation pure tableau:

a[[[0],[1],[2]],[0,2,1,3]].view('i4,i4,i4,i4') 

le résultat est C_CONTIGUOUS. Donc, il y a des détails dans [:, [...]] que je n'ai pas expliqués - spécifiquement pourquoi il produit une copie F_CONTIGUOUS.

La section mixte indexation de base/avancé doc n'avertit que la mise en page de la mémoire peut changer:

http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#combining-advanced-and-basic-indexing

Dans le cas le plus simple, il n'y a qu'un seul indice avancé. Un seul index avancé peut par exemple remplacer une tranche et le tableau de résultats sera le même, cependant, il s'agit d'une copie et peut avoir une disposition de mémoire différente. Une tranche est préférable quand c'est possible.

+0

merci! Je ne savais pas que la disposition de la mémoire pouvait changer comme ça. Pour être clair, je savais que l'indexation comme 'a [:, [0,2,1,3]' retournerait une copie, mais je ne savais pas que ça pourrait être 'F_CONTIGOUS' ou que' np.take' retourne toujours un 'C_CONTIGUOUS' (le doc numpy dit que' np.take' fait la même chose que l'indexation de fantaisie, ce qui semble faux dans ce cas). Comment géreriez-vous obtenir cette vue particulière (sans copie) d'une manière qui fonctionne toujours? Est-ce une mauvaise pratique de vérifier si le tableau est 'F \ C_CONTIGOUS'? – toes