为什么要用问句作为文章的标题呢,因为我的答案是 NO!Definitely not!
一切的一切起源于我看了一篇英文文章,说使用 Python 作科学计算有时比 Matlab 更加高效,还有那无数次见到的牛逼公式:,看的我心潮澎湃,我就寻思了,反正最近在做的那个算法用 Matlab 跑实验跑得不是太理想,要不咱也迁移一把,由于今天比较蛋疼,就决定开始尝试了,经过蛋疼的一天,我得出了开头那个结论:如果你有现成的 Matlab 算法,还是 Matlab 吧,如果你像我一样蛋疼,那就迁移吧。不相信,那就听我把遇到的一堆乱七八糟的事情娓娓道来吧,其中夹杂着我的一些弱弱的解决方案~~
.mat 数据集文件的导入
由于现有的数据集一般都是以 Matlab 的格式.mat 的形式出现的,Matlab 可以轻松的 load 语句搞定,但 Python 就不行了,花时间将 mat 文件提取成普通文本文件必然更心烦。其实这点 Python 肯定已经想到了,解决方案就是使用 Scipy 提供的函数,具体如下:
1 | import scipy as sp |
其中 datasetname 就是我们需要导入的.mat 文件,但问题又来了,导入后返回的 dataset 变量是一个“字典”的数据结构,它的 key 就是储存的变量名称,而对应的 value 就是变量的内容。这个操作并不像 Matlab 那样直接将.mat 里的变量载入 workspace,那我们当然还需要进一步使 dataset 中存储的变量暴露出来,对应的内容赋给对应的变量名称。可以查看 dataset 变量的组成,发现除了我们自己的变量,还有另外三个小东西:__globals__
,__header__
,`_version`,它们标识了.mat 文件的基本信息,但我们并不需要,所以还需要去掉它们。最终,我们通过一段代码实现:
1 | exclude = ['__globals__','__header__','__version__'] |
通过 exec 我们就实现了类似语句data = dataset["data"]
的功能。OK,到这里,第一个任务完成,撒花~~可以看到,用 Matlab 一句 load 搞定的问题,这里搞了大半天。
迁移 everything
由于我搞的是代码迁移,即将原来 Matlab 的代码改成 Python 代码,本来还觉得迁移就是稍微改改,最后发现要迁移不是一点,而是 almost everything。首先一个最严重的问题:( )
和 [ ]
的问题,这恐怕是迁移过程中最频繁的一个改动,这是为什么呢?很简单,因为 Matlab 中取矩阵元素(即 Python 中所说的‘slice’切片操作)用的是小括号,而 Python 中用的是中括号,还有比这更 fuck 的事情吗,因为函数调用也是小括号,所以放弃查找替换这不切实际的念头吧,这个恐怕只能手动。别以为这样就完事了,更琐碎的东西等着你,下面的表格可以帮助你理解什么是我说的 everything。
操作 | Matlab | Python |
---|---|---|
注释 | % |
# |
开始索引 | 1 |
0 |
矩阵连接 | [a, b] |
numpy.concatenate(a, b) |
循环和分支语句 | 未结束的条件行以,结尾结束需要end |
未结束的条件行以: 结尾结束不需要任何东西 |
产生全 0 全 1 矩阵 | zeros(m, n) 和 ones(m, n) |
numpy.zeros((m, n)) 和 numpy.ones((m, n)) |
整除问题 | / 直接取准确结果,不存在整除问题 |
/ 两遍都是整数时为整除,分子或分母需要加 float 强制转换 |
乘方 | a^b |
a**b |
矩阵向量转置 | 单引号 ' 搞定 |
没有重载 ' 操作符,需要调用 .transpose 或 .T |
结构体数组 | 直接{ } 搞定 |
{ } 指的是字典数据结构,没有结构体的概念,只能使用“对象列表”搞定 |
向量矩阵相乘 | a*b 代表正常的矩阵相乘,也就是说 a 的列数必须和 b 的行数匹配的那种 |
a*b 代表对应元素相乘,即 elementwise,a 和 b 的维数必须相等 |
a.*b 代表对应元素相乘,即 elementwise,a 和 b 的维数必须相等 |
dot(a, b) 代表正常的矩阵相乘,也就是说 a 的列数必须和 b 的行数匹配的那种 |
OK,这么些个问题需要解决,有些还是可以接受的,毕竟两个不同的语言嘛,操作符什么的不一样还行,有的就比较恶心了。其中最让人难以理解的就是 numpy 的 zeros 和 ones 不明白为啥参数一定要是一个“元组”,不知道当初创造这个时怎么想的,搞的加了两层括号。而最变态的就是矩阵向量的相乘了,Matlab 分的很清,单独的 *
号就是矩阵相乘,而 .*
就是对应元素相乘,而 Python 中单独的 *
号表示元素相乘,作用与 Matlab 恰恰相反,真正的矩阵乘法居然需要调用dot
函数才能完成,而dot
只接受两个参数,可想而知,一堆矩阵相乘的时候得多壮观啊,譬如:dot(a, dot(b, dot(c, dot(d, e) ) ) )
,类似的变态事还有矩阵连接,本来 Matlab 两矩阵放一起就能连接,Numpy 非要用一个函数,你用函数我忍了,你还用那么长一个函数concatenate
,要是连接几个矩阵咋办,一行能写下吗?大哥,我彻底凌乱了~
后话
鉴于上述的种种让人闹心的原因,我的移植工作没有坚持下去。当然,我写下这篇文章,并没有诋毁 Python 在做科学计算这方面的潜力,更没有贬低 Python 的意思,不得不承认接触 Python 越多,越觉得它牛逼,我仅仅表达的是要从 Matlab 迁移到 Python 有点得不偿失,或许一开始就直接从 Python 开始是个不错的选择,不存在迁移,直接从头开始。但如果你想我一样,有现成的 Matlab 代码了,那咱就老实 Matlab 吧~~