2013-09-02 13 views
8

Si consideri il seguente esempio semplice:pitone: NumPy: concatenazione di array di nome

x = numpy.array([(1,2),(3,4)],dtype=[('a','<f4'),('b','<f4')]) 
y = numpy.array([(1,2),(3,4)],dtype=[('c','<f4'),('d','<f4')]) 
numpy.hstack((x,y)) 

Uno sarà il seguente errore:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "C:\Python33\lib\site-packages\numpy\core\shape_base.py", line 226, in vstack 
    return _nx.concatenate(list(map(atleast_2d,tup)),0) 
TypeError: invalid type promotion 

Se array non aveva i titoli funziona

x = numpy.array([(1,2),(3,4)],dtype='<f4') 
y = numpy.array([(1,2),(3,4)],dtype='<f4') 
numpy.hstack((x,y)) 

Se rimuovo i nomi da x e y, funziona anche.

Domanda: come concatenare, vstack o hstack della serie numpy titolata? Nota: numpy.lib.recfunctions.stack_arrays non funziona bene o

risposta

3

Il problema è che i tipi sono diversi. Il "titolo" fa parte del tipo e utilizza nomi diversi da x, quindi i tipi non sono compatibili. Se si utilizzano tipi compatibili, tutto funziona bene:

>>> x = numpy.array([(1, 2), (3, 4)], dtype=[('a', '<f4'), ('b', '<f4')]) 
>>> y = numpy.array([(5, 6), (7, 8)], dtype=[('a', '<f4'), ('b', '<f4')]) 
>>> numpy.vstack((x, y)) 
array([[(1.0, 2.0), (3.0, 4.0)], 
     [(5.0, 6.0), (7.0, 8.0)]], 
     dtype=[('a', '<f4'), ('b', '<f4')]) 
>>> numpy.hstack((x, y)) 
array([(1.0, 2.0), (3.0, 4.0), (5.0, 6.0), (7.0, 8.0)], 
     dtype=[('a', '<f4'), ('b', '<f4')]) 
>>> numpy.dstack((x, y)) 
array([[[(1.0, 2.0), (5.0, 6.0)], 
     [(3.0, 4.0), (7.0, 8.0)]]], 
     dtype=[('a', '<f4'), ('b', '<f4')]) 

volte dstack, ecc, sono abbastanza intelligente per costringere i tipi in modo ragionevole, ma numpy non ha modo di sapere come combinare gli array di dischi con differenti definita dall'utente nomi dei campi.

Se si desidera concatenare i tipi di dati , è necessario creare un nuovo tipo di dati. Non commettere l'errore di pensare che la sequenza di nomi (x['a'], x['b'] ...) costituisca una vera dimensione dell'array; x e sono array 1-d di blocchi di memoria, ognuno dei quali contiene due galleggianti a 32 bit ai quali è possibile accedere utilizzando i nomi 'a' e 'b'. Ma come puoi vedere, se accedi a un singolo elemento dell'array, non ottieni un altro array come faresti se fosse davvero una seconda dimensione. È possibile vedere la differenza qui:

>>> x = numpy.array([(1, 2), (3, 4)], dtype=[('a', '<f4'), ('b', '<f4')]) 
>>> x[0] 
(1.0, 2.0) 
>>> type(x[0]) 
<type 'numpy.void'> 

>>> z = numpy.array([(1, 2), (3, 4)]) 
>>> z[0] 
array([1, 2]) 
>>> type(z[0]) 
<type 'numpy.ndarray'> 

Questo è ciò che consente agli array di record di contenere dati eterogenei; gli array di registrazione possono contenere stringhe e int, ma il compromesso è che non si ottiene tutta la potenza di un ndarray a livello di singoli record.

Il risultato è che per unire singoli blocchi di memoria, è necessario modificare lo dtype dell'array. Ci sono alcuni modi per fare questo, ma il più semplice che ho trovato comporta il poco conosciuto numpy.lib.recfunctions biblioteca (che vedo che hai già trovato!):

>>> numpy.lib.recfunctions.rec_append_fields(x, 
              y.dtype.names, 
              [y[n] for n in y.dtype.names]) 
rec.array([(1.0, 2.0, 1.0, 2.0), (3.0, 4.0, 3.0, 4.0)], 
     dtype=[('a', '<f4'), ('b', '<f4'), ('c', '<f4'), ('d', '<f4')]) 
+1

Ma questo non è quello che sto cercando .. Voglio che il nuovo array abbia titoli ereditati dal join ... ad es dopo hstack voglio avere titoli: 'a', 'b', 'c', 'd'. Perché python si preoccupa dei nomi e non solo del tipo ?! Mi fa impazzire. Penso di aver bisogno di usare Pandas piuttosto che direttamente numpy. –

+0

@HananShteingart, stai usando l'approccio sbagliato allora - devi creare un nuovo tipo di dati. Sembra che tu stia assumendo erroneamente che 'x' e' y' siano array 2-d. Loro non sono. Vedi le mie modifiche sopra. – senderle