2015-04-05 3 views
0

Я пытаюсь написать часть вложенных циклов в моем алгоритме и встретить некоторые проблемы, которые весь алгоритм занимает слишком много времени из-за этих вложенных циклов. Я довольно новичок в Python (как вы можете найти из моего нижепрофессионального кода :() и, надеюсь, кто-то может помочь мне ускорить мой код!Как ускорить вложенные циклы в Python

Весь алгоритм предназначен для обнаружения огня в нескольких массивах 1500 * 6400 Малый контекстный анализ применяется при просмотре всего массива. Контекстный анализ выполняется динамически назначенным способом размера окна. Размер окна может идти от 11 * 11 до 31 * 31 до тех пор, пока значения проверки в окнах выборки не будут достаточно следующий раунд расчета, например, как показано ниже:

def ContextualWindows (arrb4,arrb5,pfire): 
####arrb4,arrb5,pfire are 31*31 sampling windows from large 1500*6400 numpy array 
    i=5 
    while i in range (5,16): 
     arrb4back=arrb4[15-i:16+i,15-i:16+i] 
     ## only output the array data when it is 'large' enough 
     ## to have enough good quality data to do calculation  
     if np.ma.count(arrb4back)>=min(10,0.25*i*i): 
      arrb5back=arrb5[15-i:16+i,15-i:16+i] 
      pfireback=pfire[15-i:16+i,15-i:16+i] 
      canfire=0 
      i=20 
     else: 
      i=i+1 

###unknown pixel: background condition could not be characterized 
    if i!=20: 
     canfire=1 
     arrb5back=arrb5 
     pfireback=pfire 
     arrb4back=arrb4 
    return (arrb4back,arrb5back,pfireback,canfire) 

Тогда это динамические окна будут кормить в следующий раунд испытаний, например:

b4backave=np.mean(arrb4Windows) 
b4backdev=np.std(arrb4Windows) 
if b4>b4backave+3.5*b4backdev: 
    firetest=True 

Чтобы запустить весь код для нескольких массивов 1500 * 6400 numpy, потребовалось более получаса или даже больше. Просто интересно, есть ли у кого-нибудь идея, как с этим бороться? Общая идея, которую я должен приложить, была бы очень полезной!

Большое спасибо!

+2

Может быть лучше для [codereview] (http://codereview.stackexchange.com/)? – hd1

+0

не изменение сложности, но я бы использовал 'while 5 <= i <16' –

+0

Вы также могли бы изменить его на цикл for и break, с предложением else i = 20, а затем изменить тест ... Есть нет вложенных циклов, просто много нарезки, numpy должно создавать представления, поэтому не должно быть так медленно. – AChampion

ответ

1

Избегайте while петель, если скорость является проблемой. Петля поддается циклу for, так как начало и конец фиксированы. Кроме того, ваш код выполняет много копий, что на самом деле не обязательно. Переписана функция:

def ContextualWindows (arrb4,arrb5,pfire): 
    ''' arrb4,arrb5,pfire are 31*31 sampling windows from 
     large 1500*6400 numpy array ''' 

    for i in range (5, 16): 
     lo = 15 - i # 10..0 
     hi = 16 + i # 21..31 
     # only output the array data when it is 'large' enough 
     # to have enough good quality data to do calculation 
     if np.ma.count(arrb4[lo:hi, lo:hi]) >= min(10, 0.25*i*i): 
      return (arrb4[lo:hi, lo:hi], arrb5[lo:hi, lo:hi], pfire[lo:hi, lo:hi], 0) 
    else: # unknown pixel: background condition could not be characterized 
     return (arrb4, arrb5, pfire, 1) 

Для ясности я использовал принципы стиля от PEP 8 (например, расширенных комментариев, количество комментариев символов, пробелы вокруг операторов и т.д.). Копирование оконного окна arrb4 происходит здесь дважды, но только если условие выполнено, и это произойдет только один раз для вызова функции. Предложение else будет выполнено только в том случае, если for -loop запустился до конца. Нам даже не нужен break из цикла, поскольку мы полностью выходим из функции.
Сообщите нам, если это ускорит код. Я не думаю, что это будет много, но с другой стороны, в любом случае кода не так много.

+0

Конечные точки не фиксированы. Он стартует в 5, но может выйти до 16. За цикл с перерывом должен работать, но я не думаю, что это будет иметь большое значение в скорости. – hpaulj

+0

Мое предложение содержит 'break' также в' if ... then', только то, что оно полностью возвращается из функции. Это не сработает без того, чтобы ОП захотела преждевременно выйти, когда условия выполнены. Таким образом, цикл может работать до конца или может выйти до этого, как и в исходном коде.По-моему, поток поддается циклу 'for' с' break' больше, чем в цикле 'while'. Избегание копирования частей массивов, вероятно, будет иметь больше эффекта, чем это, предоставлено. – user1016274

+0

В моих тестах 1 итерация занимает 50us, все 10 500us. Быстрее разорвать, если это возможно, хорошо. Для разрыва более ясный синтаксис, но не сильно отличается по скорости. – hpaulj

0

Я провел несколько тестов времени с ContextualWindows и вариантами. Один i шаг занимает около 50us, все десять 500.

Эта простая итерация занимает примерно в то же время:

[np.ma.count(arrb4[15-i:16+i,15-i:16+i]) for i in range(5,16)] 

механизм итерации, и «копирование» массивы мелкие части времени. По возможности numpy делает вид, а не копии.

Я бы сосредоточил внимание на том, чтобы свести к минимуму количество этих count шагов или ускорить count.


Сравнивая времена для различных операций на этих окнах:

Первый раз на 1 шаг:

In [167]: timeit [np.ma.count(arrb4[15-i:16+i,15-i:16+i]) for i in range(5,6)] 
10000 loops, best of 3: 43.9 us per loop 

теперь для 10 шагов:

In [139]: timeit [arrb4[15-i:16+i,15-i:16+i].shape for i in range(5,16)] 
10000 loops, best of 3: 33.7 us per loop 

In [140]: timeit [np.sum(arrb4[15-i:16+i,15-i:16+i]>500) for i in range(5,16)] 
1000 loops, best of 3: 390 us per loop 

In [141]: timeit [np.ma.count(arrb4[15-i:16+i,15-i:16+i]) for i in range(5,16)] 
1000 loops, best of 3: 464 us per loop 

Просто индексация не требуется много времени, но тестирование условий требует значительно большего.

cumsum иногда используется для ускорения сумм по раздвижным окнам. Вместо того, чтобы брать сумму (или среднее значение) над каждым окном, вы вычисляете cumsum, а затем используете различия между фронтом и концом окна.

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

In [164]: %%timeit 
    .....: cA4=np.cumsum(np.cumsum(arrb4,0),1) 
    .....: [cA4[15-i,15-i]-cA4[15+i,15+i] for i in range(5,16)] 
    .....: 
10000 loops, best of 3: 43.1 us per loop 

Это почти в 10 раз быстрее, чем (почти) эквивалентный sum. Значения не совсем совпадают, но сроки предполагают, что это может стоить уточнить.

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