2012-02-27 14 views
16

mi sono imbattuto nel seguente stranezza in NumPy che può o non può essere un problema:Array dtype con nome: Differenza tra [0] ['nome'] e un ['nome'] [0]?

import numpy as np 
dt = np.dtype([('tuple', (int, 2))]) 
a = np.zeros(3, dt) 
type(a['tuple'][0]) # ndarray 
type(a[0]['tuple']) # ndarray 

a['tuple'][0] = (1,2) # ok 
a[0]['tuple'] = (1,2) # ValueError: shape-mismatch on array construction 

mi sarei aspettato che entrambe delle seguenti opzioni di lavoro. Opinioni?

+1

Suggerimento: quando si invia il codice a SO, si prega di inviare bit che possiamo tagliare e incollare; nel caso di Python, ciò significa usare '#' per i commenti inseriti, non '%'. – DSM

+1

Cose divertenti, vedo anche questo dando lo stesso risultato in entrambi i modi usando 1.6.1 ... –

+0

Un po 'strano, ma 'a [0] [' tuple '] [:] = (1,2)' funziona, forse c'è un indizio lì ... –

risposta

1

Questo era un bug a monte, risolto a partire da NumPy PR #5947, con una correzione in 1.9.3.

8

ottengo un altro errore di te (utilizzando 1.7.0.dev NumPy):

ValueError: setting an array element with a sequence. 

quindi la spiegazione di seguito non può essere corretto per il sistema (o potrebbe anche essere la sbagliata spiegazione per quello che vedo).

In primo luogo, si noti che l'indicizzazione di una riga di una structured array ti dà un oggetto numpy.void (vedi data type docs)

import numpy as np 
dt = np.dtype([('tuple', (int, 2))]) 
a = np.zeros(3, dt) 
print type(a[0]) # = numpy.void 

Da quello che ho capito, void è come una sorta di lista Python dal momento che può contenere oggetti di diversa tipi di dati, il che ha senso poiché le colonne in un array strutturato possono essere tipi di dati diversi.

Se invece di indicizzazione, si fetta la prima fila, si ottiene un ndarray:

print type(a[:1]) # = numpy.ndarray 

Questo è analogo a come le liste Python funzionano:

b = [1, 2, 3] 
print b[0] # 1 
print b[:1] # [1] 

affettare restituisce una versione abbreviata della sequenza originale, ma l'indicizzazione restituisce un elemento (in questo caso, uno int, sopra, un tipo void).

Pertanto, quando si suddivide le righe dell'array strutturato, è necessario aspettarsi che si comporti proprio come l'array originale (solo con meno righe). Continuando con il tuo esempio, è ora possibile assegnare ai colonne 'tupla' della prima fila:

a[:1]['tuple'] = (1, 2) 

Allora, perché ... non lo fa a[0]['tuple'] = (1, 2) lavoro?

Bene, ricordare che a[0] restituisce un oggetto void. Così, quando si chiama

a[0]['tuple'] = (1, 2) # this line fails 

si sta assegnando un tuple all'elemento 'tupla' di quel void oggetto. Nota: nonostante il fatto che hai chiamato questo indice 'tupla', è stato memorizzato come ndarray:

print type(a[0]['tuple']) # = numpy.ndarray 

Quindi, questo significa che la tupla ha bisogno di essere gettato in un ndarray. Ma, l'oggetto void non può eseguire assegnazioni (questa è solo un'ipotesi) perché può contenere tipi di dati arbitrari, quindi non sa a quale tipo eseguire il cast.Per ovviare a questo si può lanciare l'input da soli:

a[0]['tuple'] = np.array((1, 2)) 

Il fatto che otteniamo diversi errori suggerisce che la linea di cui sopra potrebbe non funzionare per voi in quanto la fusione indirizzi l'errore che ho ricevuto --- non quello che hai ricevuto .

Addendum:

Allora perché i seguenti lavori?

a[0]['tuple'][:] = (1, 2) 

Qui, si sta indicizzazione nella matrice quando si aggiunge [:], ma senza di che, sei indicizzazione nell'oggetto void. In altre parole, a[0]['tuple'][:] dice "sostituisci gli elementi dell'array memorizzato" (che viene gestito dall'array), a[0]['tuple'] dice "sostituisci l'array memorizzato" (che è gestito da void).

Epilogo:

Stranamente, l'accesso alla fila (cioè indicizzazione con 0) sembra cadere la matrice di base, ma consente ancora di assegnare alla matrice di base.

print a['tuple'].base is a # = True 
print a[0].base is a # = False 
a[0] = ((1, 2),) # `a` is changed 

Forse void non è davvero una matrice in modo da non avere una matrice di base, ... ma allora perché lo fa avere un attributo base?

+0

la taglia per te – bmu

9

L'ho chiesto sulla lista di discussione numpy. Travis Oliphant ha risposto allo here.

Citando la sua risposta:

The short answer is that this is not really a "normal" bug, but it could be considered a "design" bug (although the issues may not be straightforward to resolve). What that means is that it may not be changed in the short term --- and you should just use the first spelling.

Structured arrays can be a confusing area of NumPy for several of reasons. You've constructed an example that touches on several of them. You have a data-type that is a "structure" array with one member ("tuple"). That member contains a 2-vector of integers.

First of all, it is important to remember that with Python, doing

a['tuple'][0] = (1,2)

is equivalent to

b = a['tuple']; b[0] = (1,2)

In like manner,

a[0]['tuple'] = (1,2)

is equivalent to

b = a[0]; b['tuple'] = (1,2)

To understand the behavior, we need to dissect both code paths and what happens. You built a (3,) array of those elements in 'a'. When you write b = a['tuple'] you should probably be getting a (3,) array of (2,)-integers, but as there is currently no formal dtype support for (n,)-integers as a general dtype in NumPy, you get back a (3,2) array of integers which is the closest thing that NumPy can give you. Setting the [0] row of this object via

a['tuple'][0] = (1,2)

works just fine and does what you would expect.

On the other hand, when you type:

b = a[0]

you are getting back an array-scalar which is a particularly interesting kind of array scalar that can hold records. This new object is formally of type numpy.void and it holds a "scalar representation" of anything that fits under the "VOID" basic dtype.

For some reason:

b['tuple'] = [1,2]

is not working. On my system I'm getting a different error: TypeError: object of type 'int' has no len()

I think this should be filed as a bug on the issue tracker which is for the time being here: http://projects.scipy.org/numpy

The problem is ultimately the void->copyswap function being called in voidtype_setfields if someone wants to investigate. I think this behavior should work.

Una spiegazione di questo è dato in a numpy bug report.

Problemi correlati