2010-09-01 22 views
22

Sto provando a convertire un array bidimensionale in un array strutturato con campi denominati. Voglio che ogni riga nell'array 2D sia un nuovo record nell'array strutturato. Sfortunatamente, nulla di ciò che ho provato sta funzionando nel modo che mi aspetto.Conversione di un array numpy 2D in un array strutturato

sto iniziando con:

>>> myarray = numpy.array([("Hello",2.5,3),("World",3.6,2)]) 
>>> print myarray 
[['Hello' '2.5' '3'] 
['World' '3.6' '2']] 

voglio convertire a qualcosa che assomiglia a questo:

>>> newarray = numpy.array([("Hello",2.5,3),("World",3.6,2)], dtype=[("Col1","S8"),("Col2","f8"),("Col3","i8")]) 
>>> print newarray 
[('Hello', 2.5, 3L) ('World', 3.6000000000000001, 2L)] 

Quello che ho provato:

>>> newarray = myarray.astype([("Col1","S8"),("Col2","f8"),("Col3","i8")]) 
>>> print newarray 
[[('Hello', 0.0, 0L) ('2.5', 0.0, 0L) ('3', 0.0, 0L)] 
[('World', 0.0, 0L) ('3.6', 0.0, 0L) ('2', 0.0, 0L)]] 

>>> newarray = numpy.array(myarray, dtype=[("Col1","S8"),("Col2","f8"),("Col3","i8")]) 
>>> print newarray 
[[('Hello', 0.0, 0L) ('2.5', 0.0, 0L) ('3', 0.0, 0L)] 
[('World', 0.0, 0L) ('3.6', 0.0, 0L) ('2', 0.0, 0L)]] 

Entrambi questi approcci tentano di convertire ogni voce in myarray in un record con il dtype specificato, quindi vengono inseriti gli zeri supplementari. Non riesco a capire come ottenerlo per convertire ogni riga in un record.

Un altro tentativo:

>>> newarray = myarray.copy() 
>>> newarray.dtype = [("Col1","S8"),("Col2","f8"),("Col3","i8")] 
>>> print newarray 
[[('Hello', 1.7219343871178711e-317, 51L)] 
[('World', 1.7543139673493688e-317, 50L)]] 

Questa volta viene eseguita alcuna conversione vera e propria. I dati esistenti in memoria vengono semplicemente reinterpretati come nuovo tipo di dati.

L'array con cui sto iniziando viene letto da un file di testo. I tipi di dati non sono noti in anticipo, quindi non posso impostare il dtype al momento della creazione. Ho bisogno di una soluzione elegante e ad alte prestazioni che funzioni bene per i casi generali, poiché eseguirò questo tipo di conversione molte, molte volte per un'ampia varietà di applicazioni.

Grazie!

risposta

26

Si può "creare un array record da un (piatta) elenco delle matrici" utilizzando numpy.core.records.fromarrays come segue:

>>> import numpy as np 
>>> myarray = np.array([("Hello",2.5,3),("World",3.6,2)]) 
>>> print myarray 
[['Hello' '2.5' '3'] 
['World' '3.6' '2']] 


>>> newrecarray = np.core.records.fromarrays(myarray.transpose(), 
              names='col1, col2, col3', 
              formats = 'S8, f8, i8') 

>>> print newrecarray 
[('Hello', 2.5, 3) ('World', 3.5999999046325684, 2)] 

stavo cercando di fare qualcosa di simile. Ho scoperto che quando numpy creava una matrice strutturata da un array 2D esistente (usando np.core.records.fromarrays), considerava ogni colonna (anziché ogni riga) nell'array 2-D come un record. Quindi devi recepirlo. Questo comportamento di Numpy non sembra molto intuitivo, ma forse c'è una buona ragione per questo.

+2

con 'fromrecords' puoi evitare il' transpose() ' –

2

Ok, ho lottato con questo per un po 'ora, ma ho trovato un modo per farlo che non richiede troppo sforzo. Mi scuso se questo codice è "sporco" ....

Cominciamo con una matrice 2D:

mydata = numpy.array([['text1', 1, 'longertext1', 0.1111], 
        ['text2', 2, 'longertext2', 0.2222], 
        ['text3', 3, 'longertext3', 0.3333], 
        ['text4', 4, 'longertext4', 0.4444], 
        ['text5', 5, 'longertext5', 0.5555]]) 

Così finiamo con una matrice 2D con 4 colonne e 5 righe:

mydata.shape 
Out[30]: (5L, 4L) 

Per utilizzare numpy.core.records.array - dobbiamo fornire l'argomento di input come una lista di array così:

tuple(mydata) 
Out[31]: 
(array(['text1', '1', 'longertext1', '0.1111'], 
     dtype='|S11'), 
array(['text2', '2', 'longertext2', '0.2222'], 
     dtype='|S11'), 
array(['text3', '3', 'longertext3', '0.3333'], 
     dtype='|S11'), 
array(['text4', '4', 'longertext4', '0.4444'], 
     dtype='|S11'), 
array(['text5', '5', 'longertext5', '0.5555'], 
     dtype='|S11')) 

Questo produce una matrice separata per ogni riga di dati MA, dobbiamo le matrici input per essere da colonna in modo che cosa avremo bisogno è:

tuple(mydata.transpose()) 
Out[32]: 
(array(['text1', 'text2', 'text3', 'text4', 'text5'], 
     dtype='|S11'), 
array(['1', '2', '3', '4', '5'], 
     dtype='|S11'), 
array(['longertext1', 'longertext2', 'longertext3', 'longertext4', 
     'longertext5'], 
     dtype='|S11'), 
array(['0.1111', '0.2222', '0.3333', '0.4444', '0.5555'], 
     dtype='|S11')) 

Infine, deve essere una lista di array, non è una tupla, così abbiamo avvolgere il suddetto in lista() come di seguito:

list(tuple(mydata.transpose())) 

Questo è ordinato il nostro argomento di input dei dati ... il prossimo è il dtype:

mydtype = numpy.dtype([('My short text Column', 'S5'), 
         ('My integer Column', numpy.int16), 
         ('My long text Column', 'S11'), 
         ('My float Column', numpy.float32)]) 
mydtype 
Out[37]: dtype([('My short text Column', '|S5'), ('My integer Column', '<i2'), ('My long text Column', '|S11'), ('My float Column', '<f4')]) 

Bene, ora possiamo passare che al numpy.core.records.array():

myRecord = numpy.core.records.array(list(tuple(mydata.transpose())), dtype=mydtype) 

... e le dita incrociate:

myRecord 
Out[36]: 
rec.array([('text1', 1, 'longertext1', 0.11110000312328339), 
     ('text2', 2, 'longertext2', 0.22220000624656677), 
     ('text3', 3, 'longertext3', 0.33329999446868896), 
     ('text4', 4, 'longertext4', 0.44440001249313354), 
     ('text5', 5, 'longertext5', 0.5554999709129333)], 
     dtype=[('My short text Column', '|S5'), ('My integer Column', '<i2'), ('My long text Column', '|S11'), ('My float Column', '<f4')]) 

Voila! È possibile indicizzare dal nome della colonna come in:

myRecord['My float Column'] 
Out[39]: array([ 0.1111 , 0.22220001, 0.33329999, 0.44440001, 0.55549997], dtype=float32) 

Spero che questo aiuta come ho sprecato così tanto tempo con numpy.asarray e mydata.astype ecc cercando di arrivare a questo lavoro prima di finalmente lavorare fuori questo metodo.

8

immagino

new_array = np.core.records.fromrecords([("Hello",2.5,3),("World",3.6,2)], 
             names='Col1,Col2,Col3', 
             formats='S8,f8,i8') 

è quello che volete.

1

Se i dati inizia come un elenco di tuple, quindi creando una matrice strutturata è semplice:

In [228]: alist = [("Hello",2.5,3),("World",3.6,2)] 
In [229]: dt = [("Col1","S8"),("Col2","f8"),("Col3","i8")] 
In [230]: np.array(alist, dtype=dt) 
Out[230]: 
array([(b'Hello', 2.5, 3), (b'World', 3.6, 2)], 
     dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')]) 

La complicazione è che l'elenco di tuple è stato trasformato in una matrice di stringhe 2d:

In [231]: arr = np.array(alist) 
In [232]: arr 
Out[232]: 
array([['Hello', '2.5', '3'], 
     ['World', '3.6', '2']], 
     dtype='<U5') 

potremmo usare il noto zip* approccio alla 'trasposizione' questo array - in realtà vogliamo una doppia trasposizione:

In [234]: list(zip(*arr.T)) 
Out[234]: [('Hello', '2.5', '3'), ('World', '3.6', '2')] 

zip ci ha fornito un elenco di tuple. Ora siamo in grado di ricreare l'array con DTYPE desiderata:

In [235]: np.array(_, dtype=dt) 
Out[235]: 
array([(b'Hello', 2.5, 3), (b'World', 3.6, 2)], 
     dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')]) 

La risposta accettata utilizza fromarrays:

In [236]: np.rec.fromarrays(arr.T, dtype=dt) 
Out[236]: 
rec.array([(b'Hello', 2.5, 3), (b'World', 3.6, 2)], 
      dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')]) 

Internamente, fromarrays prende un comune approccio recfunctions: creare un array di destinazione e copiare i valori in base al nome di campo. Effettivamente:

In [237]: newarr = np.empty(arr.shape[0], dtype=dt) 
In [238]: for n, v in zip(newarr.dtype.names, arr.T): 
    ...:  newarr[n] = v 
    ...:  
In [239]: newarr 
Out[239]: 
array([(b'Hello', 2.5, 3), (b'World', 3.6, 2)], 
     dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')])