2013-05-20 13 views
7

consideri una specifica di numpy array, tipico per specificare matplotlib tracciato dei dati:Iterating two array, without nditer, in numpy?

t = np.arange(0.0,1.5,0.25) 
s = np.sin(2*np.pi*t) 

Fondamentalmente, questo memorizza le coordinate dei nostri x(x,y) punti dati della matrice t; e le risultanti coordinate (risultato di y = f (x), in questo caso sin(x)) nell'array s. Quindi, è molto conveniente utilizzare la funzione numpy.nditer avere coppie consecutive di voci t e s, che rappresenta la (x,y) coordinate di un punto di dati, come in:

for x, y in np.nditer([t,s]): 
    print("xy: %f:%f" % (x,y)) 

Quindi, sto cercando il seguente frammento come test.py:

import numpy as np 
print("numpy version {0}".format(np.__version__)) 
t = np.arange(0.0,1.5,0.25) ; print("t", ["%+.2e"%i for i in t]) 
s = np.sin(2*np.pi*t)   ; print("s", ["%+.2e"%i for i in s]) 
print("i", ["% 9d"%i for i in range(0, len(t))]) 
for x, y in np.nditer([t,s]): 
    print("xy: %f:%f" % (x,y)) 

... ed i risultati sono:

$ python3.2 test.py 
numpy version 1.7.0 
t ['+0.00e+00', '+2.50e-01', '+5.00e-01', '+7.50e-01', '+1.00e+00', '+1.25e+00'] 
s ['+0.00e+00', '+1.00e+00', '+1.22e-16', '-1.00e+00', '-2.45e-16', '+1.00e+00'] 
i ['  0', '  1', '  2', '  3', '  4', '  5'] 
xy: 0.000000:0.000000 
xy: 0.250000:1.000000 
xy: 0.500000:0.000000 
xy: 0.750000:-1.000000 
xy: 1.000000:-0.000000 
xy: 1.250000:1.000000 

$ python2.7 test.py 
numpy version 1.5.1 
('t', ['+0.00e+00', '+2.50e-01', '+5.00e-01', '+7.50e-01', '+1.00e+00', '+1.25e+00']) 
('s', ['+0.00e+00', '+1.00e+00', '+1.22e-16', '-1.00e+00', '-2.45e-16', '+1.00e+00']) 
('i', ['  0', '  1', '  2', '  3', '  4', '  5']) 
Traceback (most recent call last): 
    File "test.py", line 10, in <module> 
    for x, y in np.nditer([t,s]): 
AttributeError: 'module' object has no attribute 'nditer' 

Ah - si scopre che the iterator object nditer, introduced in NumPy 1.6 non è disponibile nella versione numpy della mia installazione Python 2.7.

Quindi, come mi piacerebbe per sostenere quella versione particolare troppo, avrei bisogno di trovare un modo di lavoro per gli anziani numpy - ma mi piace ancora la comodità di appena specificando for x,y in somearray, e ottenere le coordinate direttamente in il cappio.

Dopo un po 'pasticciare con numpy documentazione, sono arrivato fino a questo getXyIter funzione:

import numpy as np 
print("numpy version {0}".format(np.__version__)) 
t = np.arange(0.0,1.5,0.25) ; print("t", ["%+.2e"%i for i in t]) 
s = np.sin(2*np.pi*t)   ; print("s", ["%+.2e"%i for i in s]) 
print("i", ["% 9d"%i for i in range(0, len(t))]) 

def getXyIter(inarr): 
    if np.__version__ >= "1.6.0": 
    return np.nditer(inarr.tolist()) 
    else: 
    dimensions = inarr.shape 
    xlen = dimensions[1] 
    xinds = np.arange(0, xlen, 1) 
    return np.transpose(np.take(inarr, xinds, axis=1)) 

for x, y in getXyIter(np.array([t,s])): 
    print("xyIt: %f:%f" % (x,y)) 

for x, y in np.nditer([t,s]): 
    print("xynd: %f:%f" % (x,y)) 

... che sembra funzionare bene

$ python2.7 test.py 
numpy version 1.5.1 
('t', ['+0.00e+00', '+2.50e-01', '+5.00e-01', '+7.50e-01', '+1.00e+00', '+1.25e+00']) 
('s', ['+0.00e+00', '+1.00e+00', '+1.22e-16', '-1.00e+00', '-2.45e-16', '+1.00e+00']) 
('i', ['  0', '  1', '  2', '  3', '  4', '  5']) 
xyIt: 0.000000:0.000000 
xyIt: 0.250000:1.000000 
xyIt: 0.500000:0.000000 
xyIt: 0.750000:-1.000000 
xyIt: 1.000000:-0.000000 
xyIt: 1.250000:1.000000 
Traceback (most recent call last): 
    File "test.py", line 23, in <module> 
    for x, y in np.nditer([t,s]): 
AttributeError: 'module' object has no attribute 'nditer' 
$ python3.2 test.py 
numpy version 1.7.0 
t ['+0.00e+00', '+2.50e-01', '+5.00e-01', '+7.50e-01', '+1.00e+00', '+1.25e+00'] 
s ['+0.00e+00', '+1.00e+00', '+1.22e-16', '-1.00e+00', '-2.45e-16', '+1.00e+00'] 
i ['  0', '  1', '  2', '  3', '  4', '  5'] 
xyIt: 0.000000:0.000000 
xyIt: 0.250000:1.000000 
xyIt: 0.500000:0.000000 
xyIt: 0.750000:-1.000000 
xyIt: 1.000000:-0.000000 
xyIt: 1.250000:1.000000 
xynd: 0.000000:0.000000 
xynd: 0.250000:1.000000 
xynd: 0.500000:0.000000 
xynd: 0.750000:-1.000000 
xynd: 1.000000:-0.000000 
xynd: 1.250000:1.000000 

La mia domanda è - è questo il modo in cui , questo tipo di iterazione dovrebbe essere fatto, nelle versioni di numpy < 1.6.0?

risposta

3

Come circa concatenating i due vettori in un array:

for x,y in np.c_[t,s]: 
    print("xy: %f:%f" % (x,y)) 

Questo dà

xy: 0.000000:0.000000 
xy: 0.250000:1.000000 
xy: 0.500000:0.000000 
xy: 0.750000:-1.000000 
xy: 1.000000:-0.000000 
xy: 1.250000:1.000000 

Se volete iterare in modo da poter risparmiare memoria, è possibile utilizzare la funzione di itertools.izip:

for x,y in itertools.izip(t,s): 
    print("xy: %f:%f" % (x,y)) 
0

for x, y in zip(t,s):. Per gli array 1d, è davvero così semplice.

verificato funzionare sia in Python 2 e Python 3. zip() restituisce una lista python2 però, così come suggerisce DiggyF, itertools.izip() può essere più appropriato per grandi array.

Per gli array 1D, l'iterazione si sposta attraverso gli array D di ultima dimensione (N-1). Se hai a che fare con gli array N-d, questo può o non può essere quello che vuoi.

Indipendentemente da ciò, è indubbiamente portatile e l'iterazione su oggetti array è pensata per supportare questo tipo di dispositivo :)