2013-09-02 12 views
8

Rozważmy następujący prosty przykład:python: numpy: połączeniem wymienionych tablic

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

Jeden dostanie się następujący błąd:

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 

Jeśli tablica nie miał tytuły to działa

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

Jeśli usuniemy nazwy z xiy, to też działa.

Pytanie: jak konkatenować, vstack lub hstack z tablicy numpy? Uwaga: numpy.lib.recfunctions.stack_arrays nie działa dobrze albo

Odpowiedz

3

Problem polega na tym, że typy są różne. "Tytuł" jest częścią typu, a y używa różnych nazw od x, więc typy są niekompatybilne. Jeśli używasz zgodne typy, wszystko działa prawidłowo:

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

Czasami dstack, itd. Są wystarczająco inteligentny, aby zmusić typy w rozsądny sposób, ale numpy nie ma sposobu, aby wiedzieć, jak połączyć rekord z tablic inny zdefiniowany przez użytkownika nazwy pól.

Jeśli chcesz łączyć ze sobą typy , musisz utworzyć nowy typ danych. Nie popełniaj błędu myśląc, że kolejność nazw (x['a'], x['b'] ...) stanowi prawdziwy wymiar tablicy; x i y powyżej to 1-d tablice bloków pamięci, z których każda zawiera dwie 32-bitowe zmienne, do których można uzyskać dostęp za pomocą nazw 'a' i 'b'. Ale jak widać, jeśli uzyskasz dostęp do pojedynczego elementu w tablicy, nie otrzymasz innej tablicy, jak gdyby był to naprawdę drugi wymiar. Możesz zobaczyć różnicę tutaj:

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

Umożliwia to przechowywanie tablic rekordów w postaci heterogenicznych danych; tablice rekordów mogą zawierać zarówno ciągi, jak i int, ale kompromis polega na tym, że nie można uzyskać pełnej mocy parametru ndarray na poziomie poszczególnych rekordów.

Skutek polega na tym, że aby połączyć poszczególne bloki pamięci, należy zmodyfikować tablicę dtype. Istnieje kilka sposobów, aby to zrobić, ale najprostszy mogę znaleźć wiąże się z mało znaną numpy.lib.recfunctions biblioteki (co widzę już znaleźć!):

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

Ale to nie jest to, czego szukam .. Chcę, aby nowa tablica miała tytuły odziedziczone po sprzężeniu ... np po hstacku chcę mieć tytuły: "a", "b", "c", "d". Dlaczego python dba o nazwy, a nie tylko o typ ?! Doprowadza mnie do szału. Myślę, że muszę używać Pand, a nie bezpośrednio numpy. –

+0

@HananShteingart, używasz wtedy niewłaściwego podejścia - musisz stworzyć zupełnie nowy typ danych. Wygląda na to, że błędnie zakładasz, że 'x' i' y' są tablicami 2-d. Oni nie są. Zobacz moje zmiany powyżej. – senderle