2013-05-20 4 views
7

Рассмотрим спецификацию numpy массивов, типичные для определения matplotlib черчения данные:Итерация двух массивов, без nditer, в numpy?

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

В основном, это хранит x координаты наших (x,y) точек данных в массиве t; и полученные координаты y (результат y = f (x), в данном случае sin(x)) в массиве s. Затем, очень удобно использовать функцию numpy.nditer для получения последовательных пар записей в t и s, представляющем (x,y) координаты точки данных, как:

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

Итак, я пытаюсь следующий фрагмент коды в 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)) 

... и результаты:

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

Ах - получается, что the iterator object nditer, introduced in NumPy 1.6, не доступен в версии моей версии Python 2.7 версии numpy.

Итак, поскольку я хотел бы поддержать эту конкретную версию, мне нужно было найти способ работы с более старыми numpy - но мне все же хотелось бы просто указать for x,y in somearray и получить координаты непосредственно в петля.

После некоторого возиться с numpy документации, я пришел с этой getXyIter функции:

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

... который, кажется, работает хорошо

$ 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 

Мой вопрос - это путь , предполагается, что такая итерация должна выполняться в версиях numpy < 1.6.0?

ответ

3

Как насчет concatenating двух векторов в массиве:

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

Это дает

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 

Если вы хотите перебрать, так что вы можете сохранить память, вы можете использовать функцию itertools.izip:

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

for x, y in zip(t,s):. Для 1d массивов это действительно так просто.

Проверено на работу как на Python 2, так и на Python 3. zip() возвращает список на Python2, хотя, как предлагает DiggyF, itertools.izip() может быть более подходящим для больших массивов.

Для> 1D массивов итерация перемещается по последнему размерному возвращаемому массиву (N-1) D. Если вам приходится иметь дело с массивами N-d, это может быть или не быть тем, что вы хотите.

Несмотря на это, это, безусловно, портативное, и итерации на объектах массива предназначено для поддержки такого рода USECASE :)

Смежные вопросы