论操作体验,MATLAB、Julia 和 Python 哪种更好?

阅读数:2023 2019 年 7 月 17 日 11:48

论操作体验,MATLAB、Julia和Python哪种更好?

我使用 MATLAB 已经 25 年了(之前,我还使用过 MATRIXx ,一个不太成熟的衍生品)。它不是我学习的第一个编程语言,但它伴随了我在计算领域的成长。熟悉 MATLAB 对我的职业生涯很有用。不过,我们不能忽视 Python 在科学计算领域中的崛起。MathWorks 也应该有同感。他们不仅增加了在 MATLAB 中直接调用 Python 的能力,而且还借用了 Python 的一些语言特性,比如对二进制操作符的操作数进行了更激进的广播。

论操作体验,MATLAB、Julia和Python哪种更好?

我一直质疑自己在研究和教学中是否应该继续使用 MATLAB。然而,虽然使用起来得心应手,也投入了很多,但我很难调动起学习新东西的动力。

我和其他人合作写过一本介绍计算科学的 MATLAB 教材。这本书里有 40 多个函数和 160 多个计算样例,它涵盖了我认为在数值科学计算中 MATLAB 的所有基础使用方法。为了实现自我提升,并增强该书的实用性,今年我开始把这些代码用 Julia Python 实现。这种实践让我对三种语言在科学计算中的应用有了更特别的体会,下面我将进行详细说明。

先不考虑成本和开放性问题。与 Python 和 Julia 不同,MATLAB 既不是免费软件,也不是开源软件。对很多人来说,这是一个极大的区别,甚至是致命性的,但我认为这是一个技术优势。多年来,MATLAB 在很多方面发挥了远超过其它任何免费产品的实用价值,使用免费产品并希望达到一定成效,成本反而会很高。这一点对语言和生态系统的理想化诉求,需要单独进行考虑。

如果不考虑成本,可以看到这些语言起源时的诸多不同之处。MATLAB 最早出现时,侧重于数学方面,尤其是在数值运算相关的数学领域。Python 在上世纪八十年代后期出现,关注计算科学。Julia 开始于 2009 年,力求在多个方面实现平衡。

MATLAB

最开始,MATLAB 里的每个值都是双精度浮点数组,设计之初就确定了使用数组和浮点数。

浮点数的 IEEE 754 标准直到 1985 年才被采用,那时的内存是用 K 而不是用 G 来测量的。浮点数的双精度表示并不是最有效的表示字符或整数的方法,但是它们是科学家、工程师以及越来越多的数学家大部分时间里更愿意使用的格式。此外,不需要声明变量,也不需要显式地分配内存。让计算机来处理这些任务,并快速处理数据类型,解放你的大脑去思考对数据进行操作的算法。

数组之所以重要,是因为线性代数中的数值算法正在以 LINPACK EISPACK 的形式出现。但是,使用科学计算的标准载体 FORTRAN 77 来访问它们是一个多步骤的过程,包括声明变量、调用名称神秘的例程、编译代码,然后检查数据和输出文件。把矩阵乘法写成 A*B 的形式,然后马上把答案打印出来,这是一种对游戏规则的改变。

MATLAB 还使图形变得更简单、更容易访问。没有使用底层调用和硬件相关的库,只用一个 plot(x,y) 就可以得到想要的图形。它还有很多创新之处,比如嵌入复数、稀疏矩阵、构建跨平台图形用户界面的工具,以及领先的 ODE 求解程序套件,这些都使 MATLAB 在科学计算上速度非常快。

然而,对于交互式计算 (即使是长时间的计算) 来说,理想的设计并不总是有助于编写高性能软件。在许多函数之间移动数据需要同时处理许多变量,并经常查阅关于输入和输出参数的文档。对于小型项目来说,在平面名称空间中为每个磁盘文件提供一个函数非常简单,但是对于大型项目来说就比较麻烦了。如果要避免速度瓶颈,必须应用某些编程模式 (向量化、内存预分配)。科学计算现在被应用到更多领域,拥有大量不同类型的原生数据。

MathWorks 对 MATLAB 持续进行了创新:内联函数、嵌套函数、变量闭包、大量的数据类型、面向对象特性、单元测试框架等等。每一个创新都可能是一个重要问题的解决方案。但 40 年来这些变化的累积产生了副作用,削弱了概念的简单性和统一性。2009 年,我写了一本书,在不到 100 页的篇幅里,很好地涵盖了我认为 MATLAB 的基本内容。据我所知,它们现在仍可用。不过要想精通的话,还需要了解更多。

Python

从某种意义上说,Python 的历史似乎是 MATLAB 的一个镜像。两者都具有交互式命令行(现在通常叫做 REPL,即“read-eval-print loop”,交互式解释器)、可以自由定义变量和编译。不过 MATLAB 是为数值分析而开发的,而 Python 的诞生是为了满足人们内心的黑客梦。 经过改进和扩展,它们越来越趋于同化。

在我看来,Python 仍缺少数学上的吸引力。它有一些讨厌的小问题,如使用 ** 而不是 ^,用 @来表示矩阵的相乘(最近的改进!)、使用 shape 而不是 size of 来获取矩阵的大小、仍使用行数据存储等等。如果认为用 V.conj().T@D**3@V 可以很好地表达 V∗D3VV∗D3V,那真的很好笑。Python 里索引从 0 开始(与从 1 开始的索引相反)。我阅读过读取参数这篇文章,我认为这不是关键因素。很明显,这只是一个习惯问题——就像网上圣战一样的问题——因为你也可以给每种命名方式列举出不好的例子。我觉得最主要的是,我们在数学实践中从 1 开始标识向量和矩阵已经有数十年了,大部分的伪代码都做了这样的假设。

除了这些令人讨厌的地方之外,我发现 Python+NumPy+SciPy 的生态系统看起来凌乱且不一致。尽管编程语言致力于面向对象,仍存在矩阵类,但它的使用是不被鼓励而且正在逐渐消失的。也许MATLAB 轻易俘获了我的心,但是我觉得矩阵是很重要的对象类型,应该给予保留和改进。用* 可以实现对数组和矩阵不同的计算,这难道不是面向对象编程(OOP)的一大卖点吗?从这一点来看,有很多不合理的地方(为什么我要使用 spsolve 命令?稀疏据矩阵中,可以只调用 solve 吗……)。

这个生态系统有些地方看起来有点薄弱。比如,求积分和解常微分方程在 2019 年看来是一个最小的集合。据我所知,没有针对微分代数方程(DAE)、延时微分方程(DDE)、辛求解的方法或是允许内部 Krylov 子空间迭代的隐式算法。来看下这些函数的相关参考资料,它们都已经 30 年或更久了——仍然很好但远不够完整。Matplotlib 包是个了不起的成果,暂时看起来比 MATLAB 更好,但是它缺乏 3D 支持。

一些专家认为,Python 代码难以跟上编译语言的执行速度有深层次的原因。当看到“python 很慢”的搜索结果时,我觉得很可笑。Python 的拥护者提出了很多与 MATLAB 相同的论点 / 道歉,并不是说他们错了,但这不仅仅是一个有没有远见的问题

我想我知道为什么对于很多从事科学计算的人来说,Python 如此让人激动。它具有 MATLAB 风格的语法和功能,允许 REPL 运行环境;它有强大的工具,和其它语言在计算领域可以很好地配合使用;它是免费的,从长远来看,有更好的可重复性。很明显,它对很多人有效,没有必要进行语言的切换。

但对于我所知道的科学计算领域,Python 比我过去接触过的语言在学习和使用上更繁琐。我们还不知道它是会继续席卷整个社区,还是已经接近顶峰。我没有特别的预测能力,但我更倾向于认为它会呈下跌趋势。

Julia

作为后来者,Julia 有优势也有劣势。我为 Julia 的创建者鼓掌,因为我相信他们能做更好:我们需要一门开源的语言,没有使用许可限制。我们希望它有 C 的速度,Ruby 的活力。我们需要像 homoiconic 一样的语言,它像 Lisp 一样有宏,但是也像 Matlab 一样有显而易见、熟悉的数学标记。我们希望它像 Python 一样普通适用,像 R 语言一样适用于统计,像 Perl 一样适用于字符串处理,像 Matlab 处理线性代数一样强大,像 DOS 命令一样擅长粘合程序。它简单易学,却让黑客因其挑战性而欢欣。我们希望它具有互动性且能够被编译。

在很大程度上,我相信他们已经做到了。在后续的 1.0 版本上,REPL 的重要性有所下降,有一些和 MATLAB 略有差别的改动(LinRange 确实比 linspace 更好吗?)。不过这些都是小事而已。

这是我使用的第一种超越 ASCII 的语言,我对其感到不可思议的满意。比如在使用 ϕ变量和≈操作符时,它不仅仅在表面表现优异,虽然需要复杂的教学和文档,但它可以让代码更接近我们所写的数学表达式,而这才是真正的优势。

使用 Julia,我才认识到我保留了很多 MATLAB 的编程习惯,而不是因为其先天优势。很多时候,矢量化并不容易。但在 Julia 中,可以给任意函数名上添加一个点将其矢量化,这让人大开眼界。Julia 用 comprehension 来创建一个矩阵,让 MATLAB 中的嵌套循环(或 meshgrid )看起来有点过时,这样就避免通过 generator 来做简单的汇总,免得大材小用(我记得 Python 也有这个功能)。

相较于面向对象,多重分派(multiple dispatch)让很多事情变得更简单清晰。例如,假设在传统的面向对象语言中,有 Wall 和 Ball 两个类,哪个类可以检测到 Ball 碰到了 Wall 呢?是否需要一个 Room 类来做裁判呢?这类问题让我很困扰。而通过多重分派,数据和对象类型绑定在一起,但是操作数据的方法不需要和类绑定。因此,知道类的类型,但它是独立定义的。我编程很久才意识到,多重分派的有趣和理解多重分派在语言扩展上的重要性。

复制代码
function detect_collision(B::Ball,W::Wall)

数字生态系统演进速度非常快。第一个例子是 DifferentialEquations.jl ,由 Chris Rackauckas 编写。如果不尽快给这个软件颁发威尔金森奖,那真是太不应该了。

我还想看到 Julia 所承诺的基于 MATLAB 所做的速度提升。部分是因为我相对经验不足和我所承担任务需求,也因为 MathWorks 在自动化代码优化方面做了很出色的工作。在大部分时间里,我所关注的不是编程方面的问题。

用 Julia 编程让我花了一段时间才适应 (或许因为我开始变老了,思想固化了)。它让我对数据类型的思考超出了我的想象,我还总觉得自己没有按正确方式去做事。但对于日常使用,我现在更倾向于使用 Julia,而不是 MATLAB。

总结

MATLAB 是一个企业级解决方案,尤其对于工程而言。对于基本数值任务来说,它是最容易学习的。详尽的文档和多年积累的学习工具也相当重要。

MATLAB 是科学计算领域中的宝马轿车。它很昂贵,还不包括附件(工具箱)。你需要为其坚固的车体、平稳的性能和服务而买单。但它也会带来其价值不匹配的困扰

Python 是福特皮卡。他在很多地方(美国)广受欢迎。它可以做你希望的任何事,也可以做到其他汽车所不能做到的。你可能时而想要借用一下,但它提供不了纯粹的驾驶体验。

Julia 是特斯拉。它的创造有一个大胆的目标,那就是改变未来。它也可能只是一个脚注,但与此同时,你会很舒服地到达你要去的地方,并且电量会有盈余。

作者介绍:
Toby Driscoll :计算科学教授,主要研究方向为科学计算、计算软件和生命科学中数学的应用。

原文链接:
Matlab vs. Julia vs. Python

收藏

评论

微博

用户头像
发表评论

注册/登录 InfoQ 发表评论