数百种编程语言,各有优劣,各自也都有自己最为适用的场景。那么就科学计算领域而言,主流的 MATLAB、Julia、Python 会有哪些最为独特的优势呢?又存在哪些让开发者无力的缺陷?在本文中,我们将对三者进行全面对比与解析,探索科学计算各个场景中最佳的编程语言。
作者 |Toby Driscoll
译者 |槐序,责编 | 屠敏
出品 | CSDN(ID:CSDNnews)
以下为译文:
我使用MATLAB已经超过25年了。(在此之前,我甚至使用了MATRIXx,一个末期的,不值得尝试的分支,或者可能是一个噱头)这不是我学习编程的第一种语言,但是凭借它我进入数学方法时代,了解MATLAB对我的职业生涯非常有益。
但是,Python的兴起在科学计算中已经不可忽视。MathWorks一定有相同的感觉:它们不仅增加了在MATLAB中直接调用Python的能力,而且还采用了一些语言特性,例如对二元运算符的操作进行更积极广播。
这已经达到了我一直质疑我在研究和教学中继续使用MATLAB的程度。虽然大部分对我来说很容易,而且为此我投入了很多精力,但是很难鼓起勇气去真正学习新的东西。
我编写过基于MATLAB的教科书(可作入门计算数学参考书)。这本书有超过40个函数和160个计算实例,它涵盖了我认为使用MATLAB进行数值科学计算的全面基础。部分是为了自我提升,部分是为了为了增加这本书的实用性。我今年开始将代码翻译成Julia和Python。这一经历使我对关于科学计算方面的三种语言有特殊的看法,这就是下面我试图讨论的。
我将主要讨论成本和开放性问题。与Python和Julia不同的是,MATLAB既无啤酒自由也无言论自由。这对于某些人来说,的确是个巨大的区别,决定性的区别——但是我想考虑技术优势。多年来,MATLAB以许多非常有用的方式远远超过了其他任何免费产品,如果你想提高工作效率,那么成本就会受到损害。这是对语言的理想诉求和语言生态的单独考虑。
当你把成本放一边时,这些语言之间有着许多差异的有用框架在于它们的起源。MATLAB是最早尝试优先考虑数学,尤其是数字导向数学。Python在20世界80年代末开始认真,它以计算机科学为中心重点。Julia从开始在这些方面寻求更多的平衡。
MATLAB
最初,MATLAB中的每个值都是双精度浮点数数组。这个选择的两个方面,数组和浮点数,都受到设计决策的启发。
用于浮点数的IEEE 754标准直到1985年才被采用,且内存是用K而不是G来度量的。浮点双精度并不是表示字符或整数最有效的方式,但是它们是科学家、工程师以及越来越多的数学家大多数时候想要使用的。此外,不必声明变量,也不必显式分配内存。让计算机来处理这些任务,并将数据类型抛到一边,解放你得大脑去思考对数据进行操作的算法。
数组之所以重要,是因为线性代数中的数值算法正以LINPACK和EISPACK的形式出现在自己的数组中。但是科学计算中的标准承载器FORTRAN 77在涉及到变量声明、调用隐式命名的程序、编译代码,然后检查数据和输出文件方面是多步骤的过程。将矩阵乘法写为A*B并立即打印出答案是改变游戏规则的人。
MATLAB还使图形变得简单且易于访问。没有复杂的特定于机器的低级调用库,仅仅只需要plot(x,y),你几乎就能看到其他任何使用MATLAB的人都会看到的。MATLAB还有很多创新,例如复杂数字,稀疏矩阵,构建跨平台图形用户界面的工具,以及一套领先的ODE解算器套件,这些使得MATLAB成为以思维速度进行科学计算的地方。
然而,对于交互式计算而言,理想的设计,即使是冗长的计算,并不总是有助于编写良好的高性能的软件。在许多函数之间移动数据需要处理大量的变量,并需要频繁查阅有关输入和输出参数的文档。平面命名空间中的每个磁盘文件的一个功能对于一个小项目来说非常简单,但是对于大型项目来说却是一个令人头痛的问题。如果你想避免速度瓶颈,则必须应用某些编程模式(矢量化,内存预分配)。科学计算现在被应用于更多的领域,拥有大量不同的本地数据类型。等等。
MathWorks通过继续在MATLAB中进行创新来做出回应:内联函数,嵌套函数,变量闭包,多数据类型,面向对象的特性,单元测试框架等等。每项创新都可能是解决一个重要问题的方法。但是40年改变的积累却产生了破坏简单性和统一性概念的副作用。在,我写了一本书,在不到100页的篇幅里,很好地涵盖了我认为MATLAB的基本内容。据我所知,所有这些依然可用,但是现在你需要了解更多才能称自己是精通的。
Python
从某种意义上讲,Python的历史来几乎是MATLAB的镜像,两者都具有交互式命令行(现在被广泛称为REPL,即“real-eval-print loop”),并且不受变量声明和编译的限制。但是MATLAB是作为数值分析师的游乐场而创建的,而Python则是考虑黑客的情况下创建的。然后通过修订和扩展,每个都向其他受众发展。
在我看来,Python仍然缺少数学吸引力。你有一些尴尬和小烦恼,例如对于矩阵乘法用**替换^和@(最近的一项创新),一个shape而不是矩阵大小,面向行存储等。如果你认为
V.conj().T@D**3@V是一个优雅的写作方式来书写VD3V,那么你可能需要看医生。还有零索引(即与从1开始的索引相反)。我读过这些论点,我认为它们不具有决定性。这显然是一个偏好的问题——网络圣战的内容——因为你可以举出笨拙的例子来说明任何一种约定。我发现决定性的是,我们有数十年的数学实践索引向量和矩阵,大量伪代码做出了这个假设。
除了这些小烦恼外,我发现Python+NumPy+SciPy生态系统既笨拙且不一致。尽管语言主要用于面向对象,但存在一个矩阵类,但它的使用并不鼓励且被弃用。也许MATLAB使我堕落,但是我发现矩阵是一个非常重要的对象类型,可以帮助和提升。OOP的主要卖点不就是你可以用*来对数组和矩阵能做不同的事吗?在这方面还有许多不足之处。(为什么我需要一个名为spsovle的命令?我不能在稀疏矩阵上调用solve解决吗?然后继续)。
对我来说,有些地方的数字生态系统看起来有点薄弱。例如,正交和ODE(常微分方程)解法在看起来像一个最小集合。AFAICT没有方法来解决DAEs,DDEs,没有辛解法,也不允许内部Krylon迭代的隐式计算方法。看看这些方法的参考资料,它们大多30岁或者更老——仍然很好,但是距离完成还很远。Matplotlib包是一个了不起的工作,有一段时间它看起来比MATLAB好,但是发现它仍然缺少3D。
一些专家认为,对于Python代码在执行速度上很难跟上编译性语言,有着深层次原因。我对搜索“python太慢了”的结果感到很开心,Python的拥护者做了很多以前MATLAB做过相同的争论和道歉,这并不意味着他们错了,但也不仅仅是感知问题。
我想我明白为什么Python对科学计算领域的许多人来说都是如此令人兴奋。它有一些MATLAB风格式的语法和功能,可以从REPL获得。它周围有很好的工具,可以很好地与其他语言以及计算领域配合使用。它免费且具有更好的长期可复用性。很明显,它适用于很多可能没有什么理由去改变的人。
但是对于我知道如何在科学计算中做的事情来说,Python比我习惯的更像一项学习和使用的苦差事。我们暂时还不知道它是否会继续席卷整个社区,或者已经接近顶峰。我没有特殊的预测能力,但我对它未来看跌。
Julia
Julia有后来者其优点和缺点。我赞赏Julia的创作者认为他们可以做得更好:
我们想要一种具有自由许可的开源语言。希望拥有C的速度和Ruby的灵活。我们想要一种同像性语言,有像Lisp这样真正的宏,而又有MATLAB般浅显熟悉的数学符号;我们想要一门像Python一样可用于通用编程、像R般在统计分析上得心应手、像Perl般自然地处理字符串、像MATLAB般具有强大的线性代数运算能力、像shell般擅长将程序粘合在一起的语言。它简单易学,却又让严苛的黑客为之倾心;还有,我们希望它是交互式的,同时具备可编译性。
在很大程度上,我相信他们已经取得成功了。在1.0版本的后期,他们似乎稍微淡化了REPL,并且有一些无理由的慢慢远离MATLAB。(LinRange究竟比linspace更好吗?)然而,这些都是狡辩。
这是我使用的第一种超越ASCII的语言。通过使用像的变量,和≈的操作符,我仍然得不到合理的满足感。它不仅仅是表面的;能够看起来像我们写的数学表达式是其真正的优势,尽管他确实会使教学和文档变得有点复杂。
使用Julia工作让我觉得我养成了一些编程习惯,是因为MATLAB的选择,而非内在的优越性。矢量化对于许多事情并不自然。在Julia中发现,只要在函数名加一个点,你就可以对任何函数矢量化,这一点令人大开眼界。通过训练构造矩阵,相比之下,使得嵌套循环(或meshgrid技巧)看起来像是马车鞭子,并且通过生成器完全避免矩阵来进行简单的求和,感觉像没有付出代价就到手了。(我知道Python有类似的语言特性)。
多重派发这一大特性使得某些事情比面向对象做更容易和清晰,例如,假设你有传统面向对象语言中的Wall和Ball类,那个类会检测Ball和Wall之间的冲突?或者你需要一个Room类来充当裁判?这类问题让我心烦意乱。使用多重派发,数据被打包到对象类型中,但是对数据进行操作的方法不会绑定到类。因此:
functiondetect_collision(B::Ball,W::Wall)
了解类型,但是他们是独立定义, 对我来说,需要花费大量的编程来理解多重派发的概念对于扩展语言是多么有趣和潜在的重要性。
数字生态系统一直在迅速发展。我的第一个例子是DifferentialEquations.jl,由令人惊叹的Chris Rackauckas编写。如果这个软件不能马上赢得Wilkinson奖,那么系统就会崩溃。只需要去网站准备转换。
我还没有看到Julia承诺的高于MATLAB的速度提升。部分原因是我相对缺乏经验和我所做的任务,但部分原因在于MathWorks在自动化代码方面做了令人难以置信的工作。不管怎样,这不是我在大部分时间关注的编码方面。
使用Julia编程花了一段时间之后才让我感到舒服(也许只是我变老了或者固化了)。它让我对数据类型的思考超出我的想象,而且总是潜在怀疑我错过了做某件事的正确方式。但是日常使用中,我现在几乎可以转向Julia,作为MATLAB使用。
总而言之
MATLAB是企业解决方案,尤其适用于工程。对于基本数字任务它可能仍然是最容易学习的。细致的文档和数十年贡献的学习工具绝对重要。
MATLAB是科学计算界的宝马轿车。它是昂贵的,那是在你开始谈配件(工具箱)之前。你要为一个坚如磐石,平稳的性能和服务买单。它也会吸引了不成比例的仇恨。
Python是福特的皮卡。它无处不在,深受许多人(在美国)的喜爱。它可以做任何你想做的事,而且它是为做一些其他车辆不能做的事情而设计的。可能你会时不时想借一辆,但它并没有提供非常纯粹的驾驶体验。
Julia是特斯拉,它是以改变未来这一胆大目标而建立,它可能会。它也可能只是一个脚注,但与此同时,你将成功地得到你想要的,并有余力。
你怎么看?
@Hprotagonist:
就我个人而言,MATLAB在涉及到除了那翻转大矩阵之外,都彻底地让我受不了。作为线性代数特定领域工具,我当然更喜欢它而不是R,但是作为一个通用工具,它让我想拔出自己的牙齿。
它的设计并不是为了制造可维护、易于测试和易于重构的流水线工具,而从未如此,它能处理类似“简单明确的字符串和路径操作”这些基本事情,充其量是一个奇怪的仿C、Fortan、Java,且当其他任何语言当增加这些特性都会风靡一时。
我对MATLAB技术内容或多或少有一点烦恼。(我能忍受一个索引):
ans=[11]size([1])
这完全是错误的,而numpy是正确的:
In[0]np.array([1]).shapeOut[0](1,)
Python实际上是一种通用语言,具有成熟的科学堆栈,使用它的数值计算我感觉更安全,因为我可以有一个强大的测试套件和命令行输入指向我的代码,这增加了我对我的代码正在做我认为应该做的事的信心,使其易于使用。
打包或多或少是一次硬币翻转,Python打包是一个巨大的错误;matlab是不存在的(你必须自己提供每个依赖项)并且价格昂贵(其用户必须为其使用的工具箱付费,以及/或者安装MCR,且不能编辑代码)。
必要时我会维护matlab,但是我不太喜欢它。
@nimrody:
我喜欢MATLAB的一个特性是其函数是函数。参数是按值传递的,函数无法修改其参数(嗯,除了可能不常见的对象)。
如果函数不能修改其参数,Matlab将尝试优化并避免复制。Matlab(有时)也足够聪明,因此A=f(A)会在适当的位置修改A而不是复制。
这就是我对于数学导向语言的期望。如果可能的话,保持引用透明的假象,然后在内部进行优化。
MATLAB也有合理的JIT编译器,一个很好的调试器。
我不再使用MATLAB,但是它是科学计算(模拟,探索)的一个非常高效的环境。
@ggcdn:
MATLAB有它的独特,但我从来没有遇到过更好的IDE来调试“科学”代码或脚本。通过将鼠标悬停在变量上来查看当前值,能够暂停和执行某些“测试”代码,或者重写代码并继续执行,能够轻松编辑类似excel表中的数组或矩阵,当写成代码时,有看起来不像狗屎一样矩阵算法...这些是我认为非常有用的东西。我仅仅因为这些原因在我的领域(结构工程)中使用它,即使它可能会比较慢,或者更难以完成某些任务。
@ohsonice:
我的(数学研究生院)观点:
出于多种原因,MATLAB在学术界受到推崇。很容易生成可读的小脚本作为课堂示例。调试功能/IDE易于导航。学校支付许可费;编译或下载包没有任何开销工作(除非你想要做一些炫酷的)。
我参加了用Python教授的ML课程。我所有的数值分析和建模课程都依赖MATLAB于来做示例和作业。我(作为一个数学界之外的程序员)选择Julia进行研究。现在我做更多的理论研究,因为我不喜欢混合编码和运算。
一位同学,在FORTRAN平台开发PDE解算器,导师告诉他先让其在MATLAB中工作,然后再转向更快的语言。
原文:/blog/matlab-vs.-julia-vs.-python/