http://chao.lu/2012/10/python-sci-computing/
学计算,花样繁多,各有所长。
大家一般比较熟悉MATLAB这样的综合科学计算平台,需要符号计算的童鞋可能会使用Mathematica,统计爱好者喜欢R,对性能要求高的可能就直接上C/C++、Fortran 编译+运行(顺带说一句,C/C++用于科学计算的库还是挺多的,比如LAPACK用于线性代数,GSL提供复数运算、随机数、微分方程等许多数值算法)。
那么为什么还要用Python做科学计算呢?笔者觉得主要有以下几个原因:
Linux用户安装很简单,很多发行版从源里就可以安装。以笔者使用的Ubuntu为例,键入
$ sudo apt-get install python-numpy python-scipy python-matplotlib ipython python-networkx
就搞定了。如果嫌发行版提供的版本太旧,可以上官网下载安装。追求性能的童鞋还可以自行编译安装。
另外,Python库还有一个自动下载安装的好方法:使用pip,比如输入命令
$ sudo pip install networkx
就可以乖乖地下载安好。
Windows用户最好还是从官网一个个下安装包安装。或者,可以使用Enthought一体化的科学计算Python发行版(Enthought Python Distribution),里面应有尽有啦。Scipy、Numpy就是Enthought公司赞助的。
使用iPython,可以交互式地做科学计算。iPython是一个加载了科学计算包的Python解释器,同时对画图等功能提供更好的支持。
在Linux,打开终端,输入
$ ipython –pylab
就进入iPython的科学计算模式,试试看
In [1]: x=linspace(0,2*pi,1000)
In [2]: y=sin(x)
In [3]: plot(x,y,’-k’)
是不是很像MATLAB呢?
Spyder是一个专门用于Python科学计算的IDE,貌似知道的人很少,这里推荐一下。有童鞋可能会问,反正都是Python,用Eclipse这种IDE来写不成么?笔者最早也是用Eclipse写计算的脚本,后来试了试Spyder,顿时感觉方便许多。
Spyder有这些特点:
最后这条描述有些不知所云,但笔者感觉这是Spyder最爽的地方。有多爽呢?我只能说爽如MATLAB(我咋老提MATLAB。。。)
举个例子,现在我写了个脚本loaddata.py,从文件里读数据,保存在变量data里面。然后,我准备对这个数据画个图,画图的代码写在plotdata.py里面。在Spyder里,先写好loaddata.py,然后F5执行,注意选择”Execute in current Python or IPython interpreter“,于是数据加载进来了;
不过熟悉MATLAB的童鞋要注意,Spyder的加载模式还是不同于MATLAB。比如说,MATLAB里面写了一个函数文件funxx.m,后来又做了改动,那么下次调用该函数的时候改动就生效了,因为MATLAB每次都重新执行一边funxx.m的代码。但是,在Spyder里面修改过funxxLib.py(里面定义了funxx这个函数)以后,要使得改动生效,就必须按F5加载到解释器里面去。
NumPy/SciPy是Python下面科学计算最常用的库。NumPy提供基本的运算、线性代数、随机数功能,在此基础上,SciPy提供了诸如特殊函数、微积分、优化、Fourier变换等功能。
如果熟悉MATLAB等操作向量、矩阵的语言,上手会很容易:
笔者是个绘图控+排版控,科研和大作业约有一半的动力来自于画出漂亮的图、排出漂亮的文档。LaTeX当然是学术排版的不二之选,而绘图就是open question了。笔者为此试过很多软件,屡试也不爽,但matplotlib令我满意,尤其和Python的计算功能相得益彰。
笔者方才打开matplotlib官网,看到了matplotlib作者因癌症与世长辞的消息,不禁惋惜。
matplotlib做图是靠Scripting的,不能直接在图上拖来拖去,但语法和MATLAB非常相似(不得不说,MATLAB做图的一套语法设计得相当好。笔者试过gnuplot,蛋疼而知返;Mathematica做图命令,方括弧里冗长的配置也每每令笔者困惑)。
通过下面这个例子,读者应该可以对用matplotlib编程绘图有直观的印象。
import numpy as npfrom scipy.stats import normimport matplotlib.pyplot as plt # many people favor this fashionfrom matplotlib.patches import Polygonx = np.linspace(-5,5,200)y = norm.pdf(x, )x2 = np.linspace(-2,2,10)y2 = norm.pdf(x2, )x3 = np.linspace(-2,2,100)y3 = norm.pdf(x3, )vertices = [(-2,0)] + zip(x3, y3) + [(2,0)]poly = Polygon(vertices, facecolor = 'orange', edgecolor = 'k')fig = plt.figure(figsize=(5,5))ax = fig.add_subplot(111)ax.grid(True)ax.plot(x,y)ax.plot(x2, y2, 'ro')ax.add_patch(poly)ax.set_ylim(0,0.41)ax.set_xlabel('x')ax.set_ylabel('y')ax.text(0.7,0.36,r"$ \int_{-2\sigma}^{2\sigma}p(x)dx $")plt.show(fig)
笔者觉得matplotlib画的图比MATLAB更加平滑,而且有更完善的格式支持、数学字体支持。Wikipedia上的这个页面展示了一些matplotlib绘制的插图。
网络,数学上就是“图”,是经常会遇到的一种描述数据的方式,常见的有无向图、有向图、二部分图等等。操作和分析网络长久以来依赖于大家自己动手,用C/C++等自己写数据结构和算法,技术高的童鞋则可能会用Boost这样的库,但Boost比较难学而且功能有限。
NetworkX是专门用于处理、分析网络的Python库,最初的开发者是大名鼎鼎的 Los Alamos 实验室的两名研究员。NetworkX功能很全面,而且易学易用,直接以点、边、图为对象进行操作,免去了C/C++编程里面莫名奇妙的很多错误。NetworkX给用户的自由度也很大,点可以是任意的对象,点和边可以附带自定义的数据。举个例子,可以创建一个有向网络,节点是电子邮件地址(字符串),一个点到另一个点的边表示前者给后者发过信件,边的权重表示发送信件的数目。写成代码就像这样:
import networkx as nx# construct a directed graphG = nx.DiGraph()# add email addresses as nodesfor emailAddress in emailAddressList:G.add_node(emailAddress)# add edgesfor emailAdd1, emailAdd2 in emailCommunications:G.add_edge(emailAdd1, emailAdd2, weight = mailNumber(emailAdd1, emailAdd2))
NetworkX还有以下特点:
用Python做科学计算不可避免地有一些缺陷。最大的缺陷就是速度虽然不慢,但也不够快,尤其计算量巨大时相比与C/C++、Fortran的差距明显。这里就有一个trade-off:怎样平衡开发和计算的时间,比如使用Python会不会在开发上节约了一天,却在计算上多花了三天?当然,合理地用一些 trick 可以大大提高Python做计算的效率,比如向量化、合理的数据结构、用C/C++实现一些性能要求高的模块。
NetworkX也有这样的问题。我的感觉是,如果网络的规模很大(节点>50万,边>100万),NetworkX在空间和速度上就很吃力了。规模小一些的网络用NetworkX是没有问题的。