2013-09-02 13 views
8

das folgende einfache Beispiel vor:Python: numpy: Verkettung von benannten Arrays

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)) 

Man wird die folgende Fehlermeldung erhalten:

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 

Wenn Array keine Titel hatte es funktioniert

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

Wenn ich die Namen von X und Y entfernen, funktioniert es auch.

Frage: wie verkettet, vstack oder hstack des betitelten numpy array? Hinweis: numpy.lib.recfunctions.stack_arrays funktioniert nicht gut

Antwort

3

Das Problem ist, dass die Typen unterschiedlich sind. Der "Titel" ist Teil des Typs und y verwendet unterschiedliche Namen von x, daher sind die Typen inkompatibel. Wenn Sie kompatible Typen verwenden, funktioniert alles einwandfrei:

>>> 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')]) 

Manchmal dstack usw. intelligent genug sind, um Typen in einer vernünftigen Weise zu zwingen, aber numpy hat keine Möglichkeit, zu wissen, wie Rekord-Arrays mit unterschiedlichen benutzerdefinierten kombinieren Feldnamen. Wenn Sie die Datentypen verketten möchten, müssen Sie einen neuen Datentyp erstellen. Machen Sie nicht den Fehler zu denken, dass die Reihenfolge der Namen (x['a'], x['b'] ...) eine wahre Dimension des Arrays darstellt; x und y oben sind 1-d-Arrays von Speicherblöcken, von denen jeder zwei 32-Bit-Floats enthält, auf die mit den Namen 'a' und 'b' zugegriffen werden kann. Wenn Sie jedoch auf ein einzelnes Element im Array zugreifen, erhalten Sie kein anderes Array, als wenn es sich wirklich um eine zweite Dimension handeln würde. Sie können den Unterschied hier sehen:

>>> 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'> 

Dies ermöglicht Record-Arrays heterogene Daten enthalten; Record-Arrays können sowohl Strings als auch Ints enthalten, aber der Nachteil besteht darin, dass Sie nicht die volle Leistung eines ndarray auf der Ebene einzelner Datensätze erhalten.

Das Ergebnis ist, dass, um einzelne Speicherblöcke zu verbinden, müssen Sie tatsächlich die dtype des Arrays ändern. Es gibt ein paar Möglichkeiten, dies zu tun, aber die einfachste ich beinhaltet finden konnte, die wenig bekannten numpy.lib.recfunctions Bibliothek (was ich sehe, du hast schon gefunden!):

>>> 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

Aber das ist nicht das, was ich suche .. Ich möchte, dass das neue Array Titel hat, die von dem Join geerbt wurden, z nach hstack möchte ich Titel haben: 'a', 'b', 'c', 'd'. Warum kümmert sich Python um die Namen und nicht nur um den Typ ?! Macht mich verrückt. Ich denke, ich muss Pandas benutzen anstatt direkt zu nummeln. –

+0

@HananShtingart, Sie verwenden dann den falschen Ansatz - Sie müssen einen brandneuen Datentyp erstellen. Es scheint, als würden Sie fälschlicherweise annehmen, dass 'x' und' y' 2-d-Arrays sind. Sie sind nicht. Siehe meine Änderungen oben. – senderle