Более быстрый цикл, работающий с двумя значениями массива

Рассмотрим следующую функцию:

def dostuff(n, f):
    array = numpy.arange(0, n)
    for i in range(1, n):                    # Line 1                      
        array[i] = f(array[i-1], array[i])   # Line 2
    return numpy.sum(array)

Как я могу переписать строку 1/строку 2, чтобы ускорить цикл в python 3 (без использования cython)?


person Vincent    schedule 06.11.2015    source источник
comment
Вы ознакомились с numpy.vectorize? Документы говорят, что это в первую очередь удобство, но в некоторых случаях это может немного выиграть.   -  person ShadowRanger    schedule 06.11.2015
comment
Как бы вы сделали это с векторизацией Python?   -  person Vincent    schedule 06.11.2015
comment
ваша функция f полностью пользовательская? или это может быть где-то реализовано numpy? можете поделиться реализацией   -  person Nader Hisham    schedule 06.11.2015
comment
f может быть чем угодно, принимающим два целых числа и возвращающим целое число   -  person Vincent    schedule 06.11.2015
comment
Мне кажется, что вариант использования слишком прост, чтобы действительно использовать сильные стороны numpy. Я не засекал время, но, может быть, что-то вроде sum(f(x, x+1) for x in range(n-1)) действительно будет быстрее?   -  person zehnpaard    schedule 06.11.2015
comment
@zehnpaard на самом деле ваш код не дает желаемого результата, так как функция должна накапливать результаты   -  person Nader Hisham    schedule 06.11.2015
comment
@NaderHisham Ах, да, ты совершенно прав.   -  person zehnpaard    schedule 06.11.2015


Ответы (1)


Я рекомендую вам проверить этот вопрос на SO обобщенных кумулятивных функциях в NumPy/SciPy? , так как вы хотите generalized cumulative function .

также проверьте документацию scipy для функции frompyfunc здесь

func = np.frompyfunc(f , 2 , 1)

def dostuff(n,f):
    final_array = func.accumulate(np.arange(0,n), dtype=np.object).astype(np.int)
    return np.sum(final_array)

Пример


In [86]:
def f(num1 , num2):
    return num1 + num2

In [87]:
func = np.frompyfunc(f , 2 , 1)

In [88]:
def dostuff(n,f):
    final_array = func.accumulate(np.arange(0,n), dtype=np.object).astype(np.int)
    return np.sum(final_array)

In [108]:
dostuff(15,f)
Out[108]:
560

In [109]:
dostuff(10,f)
Out[109]:
165

Ориентиры


def dostuff1(n, f):
    array = np.arange(0, n)
    for i in range(1, n):                    # Line 1                      
        array[i] = f(array[i-1], array[i])   # Line 2
    return np.sum(array)

def dostuff2(n,f):
    final_array = func.accumulate(np.arange(0,n), dtype=np.object).astype(np.int)
    return np.sum(final_array)

In [126]:
%timeit dostuff1(100,f)
10000 loops, best of 3: 40.6 µs per loop

In [127]:
%timeit dostuff2(100,f)
The slowest run took 4.98 times longer than the fastest. This could mean that an intermediate result is being cached 
10000 loops, best of 3: 23.8 µs per loop
person Nader Hisham    schedule 06.11.2015
comment
За исключением того, что невекторизованная версия возвращает [0, 1, 3, 6], я думаю - person Vincent; 06.11.2015
comment
У меня проблема, это как-то сложно :), я обновил свой ответ - person Nader Hisham; 06.11.2015