2016-05-14 2 views
0

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

u = numpy.zeros((l, l)) 
wp = numpy.zeros((l,2)) 
# some code which edits u and wp 
for x in range(N): 
    wavg = numpy.dot(wp[:, 0], wp[:, 1]) 
    wp[:, 0] = 1.0/wavg*numpy.dot(u, numpy.multiply(wp[:, 0], wp[:, 1])) 

Для малых l самая медленная часть - это внешний контур. Теперь я спрашиваю себя, есть ли способ избавиться от этого цикла?

Edit: В математических терминах этот код будет выглядеть следующим образом In mathematical Terms this code would look like this

+0

В этой строке 'some code' вы выращиваете' u' и 'wp'? Какова окончательная форма этих двух массивов? Что такое 'wp [:, 0]' и 'wp [:, 1]' в уравнении? – hpaulj

+0

Это правильно. Они не меняют свою форму, но записи будут, конечно, определены в коде, который немного длиннее и, на мой взгляд, не имеет значения здесь. wp [:, 0] равно f, а wp [:, 1] соответствует w. Количество шагов времени: N – HighwayJohn

+1

Вы можете предварительно скопировать V_ij = U_ij * w_j для небольшого увеличения производительности здесь – Eric

ответ

1

Небольшое улучшение путем предварительного расчета на срок

u = np.zeros((l, l)) 
wp = np.zeros((l,2)) 
# some code which edits u and wp 

m = u*wp[:, 1] 
for x in range(N): 
    wavg = np.dot(wp[:, 0], wp[:, 1]) 
    wp[:, 0] = 1.0/wavg*np.dot(m, wp[:, 0]) 

Но мы можем сделать лучше - вместо вычисления среднего каждый раз, мы можем сделать это только на последней итерации:

m = u*wp[:, 1] 
for x in range(N - 1): 
    wp[:, 0] = np.dot(m, wp[:, 0]) 

wavg = np.dot(wp[:, 0], wp[:, 1]) 
wp[:, 0] = 1.0/wavg*np.dot(m, wp[:, 0]) 

Но есть еще одна вещь, которую мы можем сделать - это цикл может быть заменен матрицей экспоненциации:

m = u*wp[:, 1] 
wp[:, 0] = np.linalg.matrix_power(m, N-1).dot(wp[:, 0]) 
wavg = np.dot(wp[:, 0], wp[:, 1]) 
wp[:, 0] = 1.0/wavg*np.dot(m, wp[:, 0]) 

К сожалению, это выглядит медленнее. Однако, если вы можете прекомпотировать np.linalg.matrix_power(m, N-1), то это будет быстрее.

+0

Это выглядит очень красиво и работает в принципе. Это также ускоряет работу кода. Но есть большая проблема. Когда N становится большим, wavg становится очень маленьким. Для N = 6000 wavg уже 'wavg = 4.58187259646e-58'. Для еще большего N wavg будет сохранено как 0, и я получаю сообщение об ошибке. – HighwayJohn

+0

Вы можете разбить N на меньшие куски, нормализуя каждые 50 шагов или около того, и в этом случае вы можете предварительно скопировать 'np.linalg.matrix_power (m, 50)' и использовать это повторно – Eric

+0

Хорошо, я думаю, это хорошая идея. Я тоже думал об этом – HighwayJohn

4

Я до сих пор путают о форме ваших массивов, а также соотношение между кодом и уравнением.

Но только глядя на уравнение, я думаю, что это может быть вычислена как:

In [515]: n,m = 3,4 

In [516]: U = np.ones((n,m)) 

In [517]: w = np.ones((m,)) 

In [518]: f = np.ones((m,)) 

In [519]: np.einsum('ij,j,j->i',U,w,f) 
Out[519]: array([ 4., 4., 4.]) 

На данный момент я заинтересован в получении размеров, чтобы соответствовать; а не на конечных значениях. Расчет достаточно прост, что ему не нужна нотация Эйнштейна, но einsum делает перевод почти механическим.

dot эквивалент

In [520]: np.dot(U, w*f) 
Out[520]: array([ 4., 4., 4.]) 

Так как это развивается с течением времени, f итерации в зависимости от значения предыдущего (и это внешнее значения w(t)), это трудно удалить эту петлю; мы можем просто сделать содержимое быстрее.

+0

Зачем это должно быть быстрее? – HighwayJohn

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