Протокол итератора в NumPy - PullRequest
0 голосов
/ 24 марта 2019

Есть ли способ работать с итераторами вместо (например) numpy.ndarray в numpy?

Например, представьте, что у меня есть 2D-массив, и я хочу знать, есть ли строка, которая содержит только четные числа:

import numpy as np

x = np.array([[1, 2], [2, 4], [3, 6]])
np.any(np.all(x % 2 == 0, axis=1))

Есть ли способ сделать этот видвещи без создания экземпляров промежуточных объектов в памяти?(или, может быть, это уже так, и я просто не знаю) В этом примере это означало бы наличие итератора над [False True False] вместо массива.Другими словами, можем ли мы сделать что-то, что было бы эквивалентно:

has_an_even_row = False 
for row in x:
    if np.all(row % 2 == 0):
        has_an_even_row = True
        break

Мой вопрос касается не только all и any, но всех функций / методов в numpy.Если это невозможно, я задаюсь вопросом, есть ли практическая причина для того, чтобы этого не было в numpy.(Может быть, все думают, что это бесполезно, это было бы хорошей причиной)

Ответы [ 2 ]

1 голос
/ 25 марта 2019

Библиотека numpy не дает вам большого количества инструментов для использования некоторых традиционных протоколов Python, потому что она ориентирована на производительность в узкой области (числовые вычисления). Вся цель numpy состоит в том, чтобы выполнять числовые операции, которые медленны в чистом Python, гораздо быстрее (близко к максимальной скорости вашего оборудования, как код, написанный на языке более низкого уровня, например C), без потери всех из преимущества Python (такие как сборка мусора и легкий для чтения синтаксис).

Недостатком сосредоточения внимания на узком домене является то, что вы теряете некоторые преимущества более общего кода. Таким образом, ваш код цикла for может выполнять меньше работы, чем numpy, потому что он может закорачивать, прерывая итерацию, как только будет известен результат. Ему не нужно делать модуль для каждой строки, если он нашел результат, который ему уже нужен.

Но я подозреваю, что если вы протестируете его, ваш код numpy может все еще работать быстрее (тестирование на реальных данных, а не тривиальные вещи, как в вашем примере)! Несмотря на то, что он заранее вычисляет целую кучу промежуточных результатов, низкоуровневые операции выполняются намного быстрее, чем эквивалент в чистом Python, поэтому не имеет значения, что ему приходится перебирать весь массив.

1 голос
/ 25 марта 2019

Количество временных массивов может быть больше, чем вы думаете:

In [224]: x = np.array([[1, 2], [2, 4], [3, 6]])                                
In [225]: x % 2                                                                 
Out[225]: 
array([[1, 0],
       [0, 0],
       [1, 0]])
In [226]: _ == 0                                                                
Out[226]: 
array([[False,  True],
       [ True,  True],
       [False,  True]])
In [227]: np.all(_, axis=1)                                                     
Out[227]: array([False,  True, False])
In [228]: np.any(_)                                                             
Out[228]: True

В этом случае рабочая строка за строкой сэкономит на вычислении значений последней строки.

Последний шаг any может закорачиваться, останавливаясь при достижении True - это подробности реализации.

Тщательный итеративный метод без лишних вычислений будет выглядеть примерно так:

In [231]: val = False 
     ...: for row in x: 
     ...:     for col in row: 
     ...:         if col%2!=0: 
     ...:             break 
     ...:         val=(row,col) 
     ...:         break 

In [232]: val                                                                   
Out[232]: (array([2, 4]), 2)

Этот подход имел бы смысл, если бы я писал на языке C или на языке lisp, где тестирование, управление памятью и вычисления выполняются на одном уровне кода. Но это не было бы очень модульным или многоразовым.

Идея, лежащая в основе numpy, заключается в предоставлении полного набора скомпилированных строительных блоков. Эти блоки не будут оптимальными для всех задач, но в целом они быстры и просты в использовании.

Обычно рекомендуется использовать данные строительные блоки для быстрой разработки. Как только он заработает, подумайте об улучшении скорости критических по времени шагов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...