Есть два шага, которые я обычно делаю, прежде чем пытаться ускорить простой код.
- Профилируйте код, чтобы найти то, что занимает больше всего времени
- Создайте пару тестоввызов кода для проверки правильности работы оптимизированной версии
Контрольные примеры должны быть простыми и быстрыми, но при этом отражать реальные данные.Вы предоставили профилирование, но не тестировали, так что дальнейшие действия будут непроверенными.Просматривая тестовые случаи с наибольшим временем выполнения, становится ясно, что время выполнения исходит из цикла и в основном из матричных операций в нем.
119881 0.049 0.000 0.049 0.000 {метод 'reshape' объектов 'numpy.ndarray'} 239763 0,058 0,000 0,058 0,000 {встроенный метод numpy.core.multiarray.array} 119881 0,103 0,000 0,103 0,000 {метод 'diagonal' из объектов 'numpy.ndarray'} 239762 0,049 0,000 0,107 0,000 ... \ core \ numeric.py: 504 (asanyarray) 119881 0,083 0,000 0,256 0,000 ... \ core \ fromnumeric.py: 1294 (диагональ) 119881 0,105 0,000 0,439 0,000 ... \ lib \ twodim_base.py: 197 (диагональ) 839163 0,556 0,000 0,556 0,000 {встроенный метод numpy.core.multiarray.matmul}
Первая странность в том, что np.linalg.inv(smx)
не отображается в медленных операциях.Я думаю, что вы неправильно поняли совет комментаторов и полностью удалили его из основного цикла.Он все еще должен быть в основном цикле, но вызываться только один раз.
for i in range(1,len(xg)):
....
smxinv = np.linalg.inv(smx) ## Calculate inverse once per loop
dx2 = np.matmul(smxinv, pcx1)
...
ax2 = np.matmul(smxinv, px2 - np.matmul(cdx, vx2) - np.matmul(skx, dx2))
...
Самая медленная операция - matmul
.Это не так уж удивительно - оно вызывается семь раз в основном цикле.Каждый вызов имеет уникальные аргументы, поэтому я не вижу простого способа ускорить его.Далее diag
и diagonal
.Они создают диагональный массив, который имеет в основном нулевые записи, поэтому перемещение создания за пределы цикла и только обновление ненулевых записей должно обеспечить ускорение.
## Pre allocate px2 array (may not have a large effect)
px2 = np.diag(1).reshape(nst,1)
px2i = where(px2) ## Setup index of non-zero entries
for i in range(1,len(xg)):
px2[px2i] = -smx*xg[i] ## This should be equivalent
...
Это также удаляет вызов для изменения формы.Вы также можете предварительно вычислить некоторые константы и избежать нескольких вычислений в каждом цикле, но это, вероятно, не окажет большого влияния на общее время выполнения.
Каждый из этих шагов необходимо выполнить в тестовом примере, чтобы убедиться, чтоони не изменяют поведение функции, а затем профилируются, чтобы увидеть, насколько улучшено (если есть) улучшение.Хотя я ожидаю, что вы можете получить его менее чем за четыре или пять секунд, Python не сможет сравниться с производительностью скомпилированных языков.