IPython notebook目前已經成為用Python做教學、計算、科研的一個重要工具。本文介紹IPython notebook的一些基本用法,以及如何使用它調試Cython程序。
IPython Notebook使用瀏覽器作為界面,向后臺的IPython服務器發送請求,并顯示結果。在瀏覽器的界面中使用單元(Cell)保存各種信息。Cell有多種類型,經常使用的有表示格式化文本的Markdown單元,和表示代碼的Code單元。
每個代碼單元都有一個輸出區域,在Code單元中輸入代碼,按 Shift-Enter 將運行此代碼,代碼中最后一個表達式的值將輸出區域顯示。如果希望屏蔽輸出,可以在最后一條語句之后添加一個分號:”;”。此外,代碼中還可以使用print語句在輸出區域中顯示信息。
在Markdown單元中還可以直接使用Html和Javascript。
在Markdown單元中可以使用LaTeX表示數學公式,例如
fromIPython.external.mathjaximportinstall_mathjaxinstall_mathjax()
Code單元的輸出也可以顯示為數學公式,例如在單元中輸入如下代碼,將顯示為數學公式:
fromIPython.displayimportLatexLatex(r"$\sqrt{x^2+y^2}$")
SymPy的表達式也可以顯示為LaTex,例如:
%load_extsympyprintingfromsympyimport*x,y=symbols("x,y")sqrt(x**2+y**2)
以%開頭的為IPython的命令(Magic Command),這里通過%load_ext命令載入sympyprinting擴展插件,載入此插件之后,所有的SymPy表達式都顯示為數學公式。
IPython.display模塊中提供了許多顯示Python返回值的類,例如下面的代碼用Image類顯示”python.png”圖片,缺省路徑為Notebook文件所在的目錄:
fromIPython.displayimportImageImage(filename="python.png")
Image還可以用來顯示表示圖像的字符串。例如下面的代碼通過cv2的imencode()將NumPy數組轉換為一個表示PNG圖像數據的數組,然后將此數組轉換為字符串之后通過Image()將顯示為圖像:
importcv2importnumpyasnpfromIPython.displayimportImageimg=np.random.randint(0,255,(250,250,3))cv2.blur(img,(11,11),img)r,dat=cv2.imencode(".png",img)Image(dat.tostring())
此外,還可以通過HTML和Javascript將Python代碼的輸出顯示為Html,或者作為Javascript運行。
fromIPython.displayimportJavascriptJavascript("alert('ok')")
將在瀏覽器中運行Javascript代碼。
IPython中Magic命令有兩種執行方式,以%開始的命令被稱為行命令,它只對單行有效,以%%開頭的為單元命令,它放在單元的第一行,對整個單元有效。例如timeit命令可以快速測試代碼的執行效率,它可以作為行命令或者單元命令。
%timeit1+1%timeit1.0+1.0%timeit"1"+"1"
10000000 loops, best of 3: 52 ns per loop
10000000 loops, best of 3: 53.4 ns per loop
10000000 loops, best of 3: 50.9 ns per loop
%%timeits=0foriinxrange(100):s+=i
100000 loops, best of 3: 11 us per loop
每個Magic命令都可以指定參數,可以輸入timeit?查看其幫助文檔。下面讓我們看看一些常用的Magic命令。
%pylab命令將載入numpy和pylab,并且將這兩個模塊中的名字載入到全局名字空間中。缺省參數時,它使用matplotlib的缺省界面庫顯示圖表,如果帶inline參數則將圖表作為圖像插入到Notebook中。使用界面庫顯示圖像時可以使用交互工具,而將圖表直接插入到Notebook中則有利于編寫文檔。
下面的例子,plot和random是從pylab和numpy中載入的。
%pylabinlineplot(random.randn(100));
Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].
For more information, type 'help(pylab)'.
%load可以從文件或者網址載入代碼到一個新的單元中,例如下面載入某個matplotlib的示例程序,并執行:
%loadhttp://matplotlib.org/mpl_examples/pylab_examples/histogram_demo.py
#!/usr/bin/env pythonimportnumpyasnpimportmatplotlib.mlabasmlabimportmatplotlib.pyplotaspltmu,sigma=100,15x=mu+sigma*np.random.randn(10000)# the histogram of the datan,bins,patches=plt.hist(x,50,normed=1,facecolor='green',alpha=0.75)# add a 'best fit' liney=mlab.normpdf(bins,mu,sigma)l=plt.plot(bins,y,'r--',linewidth=1)plt.xlabel('Smarts')plt.ylabel('Probability')plt.title(r'$\mathrm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$')plt.axis([40,160,0,0.03])plt.grid(True)plt.show()
%prun用于代碼的執行性能分析,可以作為行命令和單元命令使用。下面的程序分析numpy.linalg.det()的性能:
%%prunforiinxrange(100):linalg.det(random.rand(10,10))
其輸出如下:
3402 function calls in 0.096 seconds
Ordered by: internal time
ncalls? tottime? percall? cumtime? percall filename:lineno(function)
100? ? 0.032? ? 0.000? ? 0.091? ? 0.001 linalg.py:1560(slogdet)
300? ? 0.022? ? 0.000? ? 0.022? ? 0.000 {method 'reduce' of 'numpy.ufunc' objects}
200? ? 0.011? ? 0.000? ? 0.012? ? 0.000 numeric.py:167(asarray)
100? ? 0.006? ? 0.000? ? 0.006? ? 0.000 linalg.py:84(_realType)
100? ? 0.005? ? 0.000? ? 0.005? ? 0.000 linalg.py:151(_assertRank2)
...
%load_ext載入IPython的擴展模塊,通過它可以載入更多的Magic命令。下面我們載入cythonmagic模塊,并使用%%cython命令編譯一個高效的頻率統計函數count()。
%load_extcythonmagic
Cython的代碼基本和Python的代碼類似,但是可以使用類型聲明,Cython可以使用這些類型聲明產生更高效的C語言代碼,并編譯成Python的擴展模塊。使用%%cython命令簡化了編譯擴展模塊的過程,它會自動創建C語言程序,編譯并載入。由于擴展模塊無法卸載,因此IPython采用的策略是每次編譯不同的代碼都會產生一個全新的擴展模塊。方便我們不退出Python環境即可運行新的代碼。
%%cythondefcount(listdata):cdef:dictresult={}inti,length=len(data)objectitemforiinrange(length):item=data[i]ifiteminresult:(result[item]).append(i)else:result[item]=[i]returnresult
下面是count()的Python版本。
fromcollectionsimportdefaultdictdefcountpy(data):result=defaultdict(list)fori,iteminenumerate(data):result[item].append(i)returnresult
先測試二者的結果是否相同:
importrandomdata=[random.randint(0,100)for_inxrange(10000)]count(data)==countpy(data)
True
然后測試它們的執行速度,可以看出Cython版本比Python的要快2倍多。在這個測試中,Cython程序也同樣使用列表和字典等對象,但是由于可以直接調用Python的C API,因此Cython版本的效率能提高幾倍。如果只是單純的數值運算,Cython能將程序提升到與C語言相近的速度。
%timeitcountpy(data)%timeitcount(data)
100 loops, best of 3: 4.52 ms per loop
1000 loops, best of 3: 1.8 ms per loop