2016-11-18 2 views
1

Ich habe folgendes numpy strukturierte Array:Ansicht von numpy strukturierten Array mit Offsets

In [250]: x 
Out[250]: 
array([(22, 2, -1000000000, 2000), (22, 2, 400, 2000), 
     (22, 2, 804846, 2000), (44, 2, 800, 4000), (55, 5, 900, 5000), 
     (55, 5, 1000, 5000), (55, 5, 8900, 5000), (55, 5, 11400, 5000), 
     (33, 3, 14500, 3000), (33, 3, 40550, 3000), (33, 3, 40990, 3000), 
     (33, 3, 44400, 3000)], 
     dtype=[('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4'), ('f4', '<i4')]) 

Das Array ist eine Teilmenge (auch eine Ansicht) der obigen Anordnung:

Ich bin versuchen, y in ein normales numpy-Array zu konvertieren. Ich möchte, dass das Array eine Ansicht ist. Das Problem ist, dass die folgende ist mir ein Fehler:

In [254]: y.view(('<i4',2)) 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-254-88440f106a89> in <module>() 
----> 1 y.view(('<i4',2)) 

C:\numpy\core\_internal.pyc in _view_is_safe(oldtype, newtype) 
    499 
    500  # raises if there is a problem 
--> 501  _check_field_overlap(new_fieldtile, old_fieldtile) 
    502 
    503 # Given a string containing a PEP 3118 format specifier, 

C:\numpy\core\_internal.pyc in _check_field_overlap(new_fields, old_fields) 
    402   old_bytes.update(set(range(off, off+tp.itemsize))) 
    403  if new_bytes.difference(old_bytes): 
--> 404   raise TypeError("view would access data parent array doesn't own") 
    405 
    406  #next check that we do not interpret non-Objects as Objects, and vv 

TypeError: view would access data parent array doesn't own 

Wenn jedoch i aufeinanderfolgenden Feldern wählen, es funktioniert:

In [255]: fields=['f1','f2'] 
    ...: 
    ...: y=x.getfield(np.dtype(
    ...:     {name: x.dtype.fields[name] for name in fields} 
    ...:     )) 
    ...: 

In [256]: y 
Out[256]: 
array([(22, 2), (22, 2), (22, 2), (44, 2), (55, 5), (55, 5), (55, 5), 
     (55, 5), (33, 3), (33, 3), (33, 3), (33, 3)], 
     dtype=[('f1', '<i4'), ('f2', '<i4')]) 

In [257]: y.view(('<i4',2)) 
Out[257]: 
array([[22, 2], 
     [22, 2], 
     [22, 2], 
     [44, 2], 
     [55, 5], 
     [55, 5], 
     [55, 5], 
     [55, 5], 
     [33, 3], 
     [33, 3], 
     [33, 3], 
     [33, 3]]) 

Ansicht Gießen scheint zu funktionieren nicht, wenn die Felder nicht aneinander grenzen, ist es eine Alternative?

Antwort

2

Ja, verwenden Sie den ndarray Konstruktor direkt:

x = np.array([(22, 2, -1000000000, 2000), 
       (22, 2,   400, 2000), 
       (22, 2,  804846, 2000), 
       (44, 2,   800, 4000), 
       (55, 5,   900, 5000), 
       (55, 5,  1000, 5000)], 
      dtype=[('f1','i'),('f2','i'),('f3','i'),('f4','i')]) 

fields = ['f4', 'f1'] 
shape = x.shape + (len(fields),) 
offsets = [x.dtype.fields[name][1] for name in fields] 
assert not any(np.diff(offsets, n=2)) 
strides = x.strides + (offsets[1] - offsets[0],) 
y = np.ndarray(shape=shape, dtype='i', buffer=x, 
       offset=offsets[0], strides=strides) 
print repr(y) 

Gibt:

array([[2000, 22], 
     [2000, 22], 
     [2000, 22], 
     [4000, 44], 
     [5000, 55], 
     [5000, 55]]) 

Btw, wenn alle Felder in der ursprünglichen Anordnung die gleiche dtype haben, ist es viel einfacher, zuerst Erstellen Sie eine Ansicht für dieses Array, gefolgt von einer Slicing-Operation. wie oben für das gleiche Ergebnis:

y = x.view('i').reshape(x.shape + (-1,))[:,-1::-3] 
+0

Super! Vielen Dank. – snowleopard

+0

Müssen die Felder kontinuierlich sein, damit dies funktioniert? ['f4', 'f1'] ist immer noch kontinuierlich von meinem Verständnis. Ist das der Grund dafür? – snowleopard

+0

Versuchen Sie 'Felder = ['f4', 'f3', 'f1']'. Offsets sind '[12, 8, 0]' - es gibt eine -4 und -8 Lücke. 'strides' können nicht mit beiden umgehen. – hpaulj

1

Das Folgende ist ein wenig verwirrend - aber das Wesentliche ist, dass für diese Art von view zu arbeiten muss es in der Lage sein, auf die Felder mit regelmäßigen Array-Schritten und Formen zugreifen. Das Auslesen von ['f1', 'f3'] schlägt aus dem gleichen Grund fehl, dass np.ones((12,4))[:,[0,2]] eine Kopie erzeugt.

========

In Ihrer strukturierten Array wird jeder Datensatz als 4 * 'I4' Bytes gespeichert. Das Layout ist kompatibel mit einem (n, 4) 'I4' Array:

In [381]: x.__array_interface__['data'] # databuffer pointer 
Out[381]: (160925352, False) 
In [382]: x.view(('i',4)).__array_interface__['data'] 
Out[382]: (160925352, False)   # same buffer 
In [387]: x.view(('i',4)).shape 
Out[387]: (12, 4) 

aber wenn ich nehme verschiedene Scheiben dieses Arrays

In [383]: x.view(('i',4))[:,[0,1]].__array_interface__['data'] 
Out[383]: (169894184, False)  # advance indexing - a copy 

In [384]: x.view(('i',4))[:,:2].__array_interface__['data'] 
Out[384]: (160925352, False)  # same buffer 

Aber Auswahl von [ 'F1', 'F3'] entspricht: x.view(('i',4))[:,[0,2]], eine weitere Kopie.

Oder schauen Sie sich die Schritte an. Mit den ersten zwei Feldern

In [404]: y2=x.getfield(np.dtype({name: x.dtype.fields[name] for name in ['f1','f2']})) 
In [405]: y2.dtype 
Out[405]: dtype([('f1', '<i4'), ('f2', '<i4')]) 
In [406]: y2.strides 
Out[406]: (16,) 
In [407]: y2.view(('i',2)).strides 
Out[407]: (16, 4) 

Um dieses Array als nur ints zu sehen, es von 16 Zeilen Schritt kann und durch 4 Spalten zu treten und nur 2 Spalten nehmen.

Oder schauen Sie sich die volle Wörterbuch für die 4-Säule und 2 Spalte Fälle

In [409]: x.view(('i',4)).__array_interface__ 
Out[409]: 
{'data': (160925352, False), 
'descr': [('', '<i4')], 
'shape': (12, 4), 
'strides': None, 
'typestr': '<i4', 
'version': 3} 
In [410]: y2.view(('i',2)).__array_interface__ 
Out[410]: 
{'data': (160925352, False), 
'descr': [('', '<i4')], 
'shape': (12, 2), 
'strides': (16, 4), 
'typestr': '<i4', 
'version': 3} 

gleichen Schritten und dtype, nur andere Form. Der Fall y2 funktioniert, weil er auf die gewünschten Bytes mit Schreiten zugreifen und 2 Spalten ignorieren kann.

Wenn ich schneide aus zwei mittleren Spalten des 4-Säule Falles bekomme ich einen Blick - gleichen Datenpuffer, aber mit einem Offset:

In [385]: x.view(('i',4))[:,2:4].__array_interface__['data'] 
Out[385]: (160925360, False) 

aber getfield mit diesen zwei Feldern gibt die gleichen Fehler wie mit [ 'f1', 'f3']:

In [388]: y2=x.getfield(np.dtype({name: x.dtype.fields[name] for name in ['f2','f3']})).view(('i',2)) 
... 
ValueError: new type not compatible with array. 

view nicht, dass die Datenpuffer implementieren kann ausgeglichen, dass Dosen schneiden.

========

Blick wieder auf die 2 mittleren Felder:

In [412]: y2=x.getfield(np.dtype({name: x.dtype.fields[name] for name in ['f2','f3']})) 
    ...: 
In [413]: y2 
Out[413]: 
array([(2, -1000000000), (2, 400), (2, 804846), (2, 800), (5, 900), 
     (5, 1000), (5, 8900), (5, 11400), (3, 14500), (3, 40550), 
     (3, 40990), (3, 44400)], 
     dtype={'names':['f2','f3'], 'formats':['<i4','<i4'], 'offsets':[4,8], 'itemsize':12}) 
In [414]: y2.__array_interface__['data'] 
Out[414]: (160925352, False) 

y2 in der ursprünglichen Datenbank Start zeigt. Es erreicht den Offset mit den dtype Offsets. Vergleichen Sie das mit dem Offset in In[385].

+0

Vielen Dank für die sehr ausführliche Antwort, ich habe erwartet, den Prozess mit kontinuierlichen Feldern zu arbeiten, aber ich habe auch bemerkt, dass es nur mit einer Scheibe arbeitet das erste Feld enthält. Ich verstehe, dass, wenn die Felder nicht kontinuierlich sind, eine erweiterte Indizierung ausgelöst wird, die eine Kopie zurückgibt. Ich verstehe nicht, warum es mit einigen kontinuierlichen Feldern nicht funktioniert, da dies im Wesentlichen eine Scheibe zu sein scheint. – snowleopard

+0

Ich habe einige Informationen über die f2/f3 'Scheibe' hinzugefügt. Beide Methoden erfordern eine Art Offset, aber sie verwenden unterschiedliche Methoden. Man versetzt den Datenpufferzeiger und verwendet von dort aus reguläres Schreiten. Der andere verwendet die Offsets "dtype" und den ursprünglichen Datenpufferzeiger. – hpaulj

Verwandte Themen