Как сделать несколько вызовов функций для строкового массива numpy за одну итерацию? - PullRequest
0 голосов
/ 27 мая 2020

Вот код:

>>> import numpy as np
>>> words = np.array(['   woRd ', '  amaZINg  ', '   PossiblE    '])
>>> words_fixed = np.char.lower(np.char.strip(words))
>>> words_fixed
array(['word', 'amazing', 'possible'], dtype='<U15')

Работает отлично.

Насколько я понимаю, этот код принимает сложность O(2n), поскольку он вызывает strip на всех сначала элементы, возвращая новый numpy array, а затем вызывая lower для всех элементов этого массива и возвращая еще numpy array.
Теперь я понимаю, что O(2n) в конечном итоге O(n), но можно ли это сделать в O(n) сложности?

Есть ли способ сложить несколько вызовов функций и вызвать их все за одну итерацию?

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

1 Ответ

1 голос
/ 27 мая 2020

Список слов и эквивалентный массив:

In [153]: words = ['   woRd ', '  amaZINg  ', '   PossiblE    ']                         
In [154]: arr = np.array(words)                                                          

Ваша операция с массивом:

In [155]: np.char.lower(np.char.strip(arr))                                              
Out[155]: array(['word', 'amazing', 'possible'], dtype='<U15')

Эквивалентное понимание списка:

In [156]: [word.strip().lower() for word in words]                                         
Out[156]: ['word', 'amazing', 'possible']

или с использованием генератор внутри понимания:

In [159]: [word.lower() for word in (word.strip() for word in words)]                        
Out[159]: ['word', 'amazing', 'possible']

Некоторые тайминги:

In [160]: timeit [word.lower() for word in (word.strip() for word in words)]
1.33 µs ± 10.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [161]: timeit [word.strip().lower() for word in words]                                  
848 ns ± 13.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [162]: timeit np.char.lower(np.char.strip(arr))                                       
12.3 µs ± 143 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Понимание списка происходит быстрее всего. Иногда операции numpy лучше масштабируются, но, исходя из прошлого опыта работы с функциями np.char, я не думаю, что здесь это произойдет. Функции np.char являются простыми оболочками для строковых методов Python.

Хорошо, есть способ вызвать два метода python в строке и выполнить итерацию в numpy:

In [164]: np.frompyfunc(lambda word: word.strip().lower(),1,1)(arr)                        
Out[164]: array(['word', 'amazing', 'possible'], dtype=object)
In [165]: timeit np.frompyfunc(lambda word: word.strip().lower(),1,1)(arr)                 
6.87 µs ± 14.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Поскольку его время составляет половину связанного np.char, можно сказать, что он сокращает временную сложность с 2n до n.

O(n) отсчетов имеет смысл только в том случае, если вы используете те же методы итерация. Благодаря сочетанию интерпретируемого и скомпилированного кода, используемого Python / numpy, O (n) имеет ограниченное значение. Более важно оптимально использовать быстрее компилируемый код.

...