如何用 Python 科學計算中的矩陣替代循環?

據說這樣可以提高在數據量較大時的程序運行速度?哪位大俠能告訴小弟一下怎麼操作啊?

謝謝了!


比如求一個平面穩態導熱問題,控制方程就是拉普拉斯方程:

 
abla^{2}=0

(我才發現原來有[插入公式]這個功能)

按照最簡單的毅種循環來寫就是:

def laplace(u):
nx, ny = u.shape
for i in xrange(1,nx-1):
for j in xrange(1, ny-1):
u[i,j] = ((u[i+1, j] + u[i-1, j]) * dy2 +
(u[i, j+1] + u[i, j-1]) * dx2) / (2*(dx2+dy2))

有兩個嵌套循環,還不算外部迭代的。

Python嵌套循環非常慢,盡量不要超過兩層。

邊界條件是底邊為1,其餘是0.

因為我是忠實的藍貓教信徒,所以迭代3000次。

耗時44秒。

用NumPy的數組計算重新寫拉普拉斯方程:

def mat_laplace(u):
u[1:-1,1:-1] = ((u[2:,1:-1]+u[:-2,1:-1])*dy2 +
(u[1:-1,2:] + u[1:-1,:-2])*dx2) / (2*(dx2+dy2))

注意需先導入Numpy庫:

import numpy as np

數組初始化用NumPy里的zeros

u = np.zeros([N, N])
u[0] = 1

還是迭代3000次,耗時0.33秒。


熟練使用 numpy 和 pandas 裡面自帶的 functions 會比自己寫 for loop 快很多倍,比如金融裡面求最大回撤,常規做法是一個 for loop。如果用 pandas.rolling_max,結果如下:

對於一個一億個點的時間序列 ts, 用常規演算法在 Python 裡面要算 1min39s,而把 ts 先變成 pandas.Series 再用 rolling_max 只需要不到 3s. 裡面的具體演算法不是很清楚,希望 CS 專業人士來回答。

還有很多其他的例子,樓上也提到了用 map, reduce, filter + lambda functional programming 的淫招,或者配合 pandas 的 groupby 使用。還有對於金融中的因子數值計算,強烈安利 numexpr (@gygigi khgjkbj 提到的)。下次有空寫個 numexpr library 在因子計算中的應用。


你們都不知道numexpr的么←_←

比numpy還黑的科技→_→

雖然能用的運算沒多少吧但是對大矩陣的整體運算還是很快的←_←


用numpy, Cython, 或者 weave

Speed up Python

SciPy官網有關於如何提高Python Performance的教程

PerformancePython

用Pyrex/Cython或者weave基本上可以達到C++的速度。

Laplace的例子,500*500矩陣,100次循環。


最近正好在學numpy這個模塊。題主可以看看這個教程,不是很全,但是科學計算方面還是有不少東西的:NumPy-快速處理數據

引用教程中的代碼:

import time
import math
import numpy as np

x = [i * 0.001 for i in xrange(1000000)] # 初始化數組0.000~999.999
start = time.clock()
for i, t in enumerate(x): # 用循環計算正弦值
x[i] = math.sin(t)
print "math.sin:", time.clock() - start

x = [i * 0.001 for i in xrange(1000000)]
x = np.array(x) # 初始化矩陣(這裡是一維)
start = time.clock()
np.sin(x,x) # numpy的廣播計算(代替循環)
print "numpy.sin:", time.clock() - start

# 輸出
# math.sin: 1.15426932753
# numpy.sin: 0.0882399858083

可以看到用矩陣速度快多了,但是這是數據規模較大的情況。數據量小時,還是循環快,拿大炮打蚊子本就不合適嘛。


numpy和pandas.DataFrame的矩陣運算可以廣播,可以map。


想要快,就內嵌C,Python是解釋性語言,會比較慢。

有成熟的計算軟體時用的C/C+++python的模式,核心演算法和耗時最多的邏輯用C/C++,其他用python.


第一個技巧是,用map和lambda表達式來生成你要的迭代參數,比如生成一個平方表:map(lambda x: x*x, xrange(100)),這是個黑科技,可以很快速的生成你需要的循環參數;

第二個技巧是,熟練使用矩陣掩膜(mask)來簡化循環,比如把矩陣a中小於100的值都置零:a[a&<100] = 0,比循環快很多;

第三個技巧是,多使用各種庫,如numpy, scipy(signal庫簡直好頂贊),如果你做圖像,opencv庫是唯一的選擇。

大致是這樣,實際應用中更多的是前兩個trick混合使用。


推薦閱讀:

在使用pip list時出現DEPRECATION是怎麼回事?怎麼解決?

TAG:Python | Python3x | 科學計算 | Python入門 | Python使用技巧 |