2012-09-30 3 views
10

Ich versuche zu verstehen, wie man mit nditer arbeitet, um eine Reduktion zu machen, in meinem Fall ein 3d-Array in ein 2d-Array zu konvertieren.Wie eine Reduktion mit numpy.nditer in der ersten Achse zu tun

Ich folgte die Hilfe hier http://docs.scipy.org/doc/numpy/reference/arrays.nditer.html und es geschafft, eine Funktion zu erstellen, die der Eingangs Reduktion über die letzte Achse gilt. Mit dieser Funktion

def nditer_sum(data, red_axes): 
    it = numpy.nditer([data, None], 
      flags=['reduce_ok', 'external_loop'], 
      op_flags=[['readonly'], ['readwrite', 'allocate']], 
      op_axes=[None, red_axes]) 
    it.operands[1][...] = 0 

    for x, y in it: 
     y[...] = x.sum() 

    return it.operands[1] 

ich etwas Gleichwertiges zu data.sum bekommen kann (Achse = 2)

>>> data = numpy.arange(2*3*4).reshape((2,3,4)) 
>>> nditer_sum(data, [0, 1, -1]) 
[[ 6 22 38] 
[54 70 86]] 
>>> data.sum(axis=2) 
[[ 6 22 38] 
[54 70 86]] 

So etwas Gleichwertiges zu data.sum bekommen (Achse = 0) ich, dass es, obwohl war genug, um das Argument red_axes zu [-1, 0,1] zu ändern, aber das Ergebnis ist ganz anders.

>>> data = numpy.arange(2*3*4).reshape((2,3,4)) 
>>> data.sum(axis=0) 
[[12 14 16 18] 
[20 22 24 26] 
[28 30 32 34]] 
>>> nditer_sum(data, [-1, 0, 1]) 
[[210 210 210 210] 
[210 210 210 210] 
[210 210 210 210]] 

In dem for-Schleife innerhalb nditer_sum (für x, y in it :), der Iterator ist 2mal Looping und ein Array mit der Länge 12 jedes Mal statt Looping 12mal und gibt ein Array geben der Länge 2 jedes Mal. Ich habe lesen Sie die numpy Dokumentation mehrmals und googelte über diese kein Erfolg. Ich benutze numpy 1.6 und python 2.7

+0

-1 in op_axes wird als "neue Achse" dokumentiert, ist es das, was Sie versuchen, machen? Auch Dokumentationen Feeds [[Größe x], [Größe y], [Größe z]] in op_axes, während Sie [None, [Größe 3]] drücken, ist das beabsichtigt? –

+0

Die [Dokumentation] (http://docs.scipy.org/doc/numpy/reference/generated/numpy.nditer.html) sagt "ein Operand ist eine Zuordnung von den Dimensionen des Iterators zu den Dimensionen des Operanden" ... Was auch immer das heißt. Im aktuellen Beispiel habe ich den Code im Tutorial [iterating over arrays] (http://docs.scipy.org/doc/numpy-dev/reference/arrays.nditer.html#reduction-iteration) kopiert, das funktioniert, aber nur mit der letzten Achse. In dem Beispiel hat das 3D-Array op_axes None (was äquivalent zu [-1, -1, -1] zu sein scheint) und die 2d-Achse hat [0, 1, -1] – Sergio

+0

I, aber das ändert [0,1, - 1] bis [-1, 0, 1] würde die Reduktion auf der ersten Achse tun, aber es funktioniert nicht.Meine Frage ist, wie man die Reduktion auf einer beliebigen Achse durchführt. – Sergio

Antwort

0

Ändern der Zeile y[...] = x.sum() zu y[...] += x behebt es (wie im Beispiel here).

+0

Aber das möchte ich nicht machen. Ich verwende eine komplexere Funktion, die eine Reihe von Operationen auf x ausführt. Stellen Sie sich vor, dass anstelle der Summe ist "die Summe nach dem Clipping der 10% niedriger und höher von x" – Sergio

+0

Ich sage nur, dass das Update das Verhalten mit numpy.sum mit einer Achse festgelegt, die die Frage schien. .. Vielleicht sollten Sie Details zur Frage hinzufügen. – Benjamin

1

Der axis=0 Fall funktioniert ordnungsgemäß, wenn der nditer Auftrag in F geändert wird. Jetzt gibt es 12 Schritte mit Arrays der Größe (2,), wie Sie wollten.

it = np.nditer([data, None], 
     flags=['reduce_ok', 'external_loop'], 
     op_flags=[['readonly'], ['readwrite', 'allocate']], 
     order='F',  # ADDED to loop starting with the last dimension 
     op_axes=[None, red_axes]) 

Aber es ist keine Lösung, wie dies für Mitte axis=1 Fall.

Ein anderer Ansatz zur Iteration ausgewählter Dimensionen besteht darin, einen Iterator 'multi_index' auf einem reduzierten dimensionalen Array zu erstellen. Ich entdeckte in https://stackoverflow.com/a/25097271/901925, dass np.ndindex diesen Trick verwendet, um eine "flache Iteration" durchzuführen.

Für die axis=0 Fall ist diese Funktion funktioniert:

def sum_1st(data): 
    y = np.zeros(data.shape[1:], data.dtype) 
    it = np.nditer(y, flags=['multi_index']) 
    while not it.finished: 
     xindex = tuple([slice(None)]+list(it.multi_index)) 
     y[it.multi_index] = data[xindex].sum() 
     it.iternext() 
    return y 

Oder auf jede Achse verallgemeinert:

def sum_any(data, axis=0): 
    yshape = list(data.shape) 
    del yshape[axis] 
    y = np.zeros(yshape, data.dtype) 
    it = np.nditer(y, flags=['multi_index']) 
    while not it.finished: 
     xindex = list(it.multi_index) 
     xindex.insert(axis, slice(None)) 
     y[it.multi_index] = data[xindex].sum() 
     it.iternext() 
    return y 
Verwandte Themen