2012-06-18 2 views
7

У меня есть алгоритм расчета средней скорости в чистом питоне:Numpy означает, с условием

speed = [...] 
    avg_speed = 0.0 
    speed_count = 0 
    for i in speed: 
     if i > 0: # I dont need zeros 
      avg_speed += i 
      speed_count += 1 

    if speed_count == 0: 
     return 0.0 

    return avg_speed/speed_count 

Есть ли способ, чтобы переписать эти функции с Numpy?

ответ

9
import numpy as np 

def avg_positive_speed(speed): 
    s = np.array(speed) 
    positives = s > 0 
    if positives.any(): 
     return s[positives].mean() 
    else: 
     return 0. 


speed = [1., 2., 0., 3.] 
print avg_positive_speed(speed) 
# prints 2.0 

print avg_positive_speed([0., 0.]) 
# prints 0.0 
3

Я знаю, что вы хотите numpy решения, так что это не отвечает, что критерий (@ ранее пост eumiro, безусловно, делает), но только в качестве альтернативы, вот оптимизированная версия Python, который неожиданно (для меня по крайней мере,) оказалось довольно быстрым!

speeds = [i for i in speed if i > 0] 
return sum(speeds)/(1.0 * len(speeds)) if sum(speeds) > 0 else 0.0 

Может показаться интересным сравнить это с реализацией numpy (или оригинальной) с точки зрения скорости.

In [14]: timeit original(speed)    # original code 
1000 loops, best of 3: 1.13 ms per loop 

In [15]: timeit python_opt(speed)   # above Python 2 liner 
1000 loops, best of 3: 582 us per loop 

In [16]: timeit avg_positive_speed(speed) # numpy code 
1000 loops, best of 3: 1.2 ms per loop 

где

speed = range(10000) 

Я бы подумал, что numpy будет иметь преимущество здесь .. Кто-нибудь знает, почему он тащит?

Update:

со speed = range(100000):

In [19]: timeit original(speed) 
100 loops, best of 3: 12.2 ms per loop 

In [20]: timeit python_opt(speed) 
100 loops, best of 3: 11 ms per loop 

In [21]: timeit avg_positive_speed(speed) 
100 loops, best of 3: 12.5 ms per loop 

До сих пор не уверен, что numpy является хорошим инструментом для это частности проблемы, если не является огромного числом скоростей :)

Как работает память numpy? в какой-то момент может возникнуть некоторые ограничения.

+0

Попробуйте увеличить. С 1000, преобразование из списка в массив доминирует в таймингах. –

+0

@JoeKington просто делает это сейчас .. :) – Levon

+2

Имейте в виду, что преобразование большого списка в массив numpy является относительно медленным процессом. Если данные уже представляют собой массив numpy (который использует _far_ меньше памяти, чем список), то версии numpy будут намного быстрее. В противном случае вы не увидите большой разницы для одной операции, так как большая часть времени будет съедена, преобразуя список в массив. –

16

Функция numpy.average может получить weights аргумент, где вы можете поместить булево массив генерируемого из некоторого условия применительно к самой матрице - в этом случае элементом является больше чем 0:

average_speed = numpy.average(speeds, weights=(speeds > 0)) 

Надеется, что это помогает

+4

+1, этот совет «весов» замечателен! – eumiro

+0

Это решение замечательно, спасибо. –

9

Я удивлен, что никто не предложил кратчайшее решение:

speeds_np = np.array(speeds) 

speeds_np[speeds_np>0].mean() 

Пояснение:

speedsNp > 0 создает булевой массив того же размера, удовлетворяющий равенству (in). Если он подан в speedsNp, он дает только соответствующие значения speedNp, где значение булевой матрицы равно True. Все, что вам нужно сделать, это просто взять mean() результата.

+1

Это, безусловно, лучший ответ здесь. Спасибо @TimY – mjp

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