Matlab 中 datestr 和 datenum 函数效率问题

作者: , 共 2195 字

最近用 Matlab 写了个东西,运行效率不如我意。用 Profiler 跟踪了一下,结果让我大吃一惊。其中三分之一的时间花费在 datestr 这个函数上,六分之一的时间花费在 save 和 load 数据上。这里先谈前一个问题,关于 save 和 load 的效率以后再谈。

1. datestr 和 datenum 的功能

这两个函数的功能需要从日期(和时间)的表示方法谈起。一个日期,它可以用一个字符串来表示,比如"2010-10-30 13:45:17",或"Oct.30,2010 3:45:17 PM", Matlab 内置 31 种默认表示方法,同时还支持自定义格式。这种字符串的表示方式具有可读性,多用于外部展现。或者用一个向量来表示日期,比如 [2010 10 30 13 45 17] ;日期还可以为一个序列值,比如上面的日期可以为 73444.1573113426。在进行数据处理时常使用数字型的日期,因为储存、比较、计算都要快得多。Excel 表格中日期外面看上去是一个字符串,但在内部存储的是一个数字,就是基于这个原因。

这样 datestr 和 datenum 的功能就很清晰了, datestr 把指定日期转化为字符串形式, datenum 则获取指定日期的序列值。

注: Excel 的日期的数字表示和 Matlab 不一样,具体情况参见Matlab、Excel、SQL 中的日期的数字序列形式。另外 Excel 的日期类型在 vba 的 match 函数上有一个 bug ,参见VBA 中的 Date 类型的匹配问题

2. datestr 和 datenum 的效率

直接运行 10000 次 datenum :

>> tic; for i = 1:10000, a = datenum('2010-10-10'); end; toc
Elapsed time is 26.869241 seconds.

通过 Profiler 发现大部分时间都消耗在判断输入的字符串表示格式上,通过直接指定输入格式,可将速度加快 5 倍:

>> tic; for i = 1:10000, a = datenum('2010-10-10', 'yyyy-mm-dd'); end; toc
Elapsed time is 5.048942 seconds.

datestr 函数要好一些:

>> tic; for i = 1:10000, a = datestr(734421); end; toc
Elapsed time is 1.760489 seconds.

够快吗?在处理大数据集时还是不够快。下面有些简单的方法让 datenum 再快 100 倍,让 datestr 再快 5 倍。

3. 提速方法

如果不想改变自己的使用习惯和使用别的替代函数(比如为了保持兼容性),一个直接的办法(习惯)是在使用 datenum 时对输入指定格式,比如 datenum('2010-10-10', 'yyyy-mm-dd')要比 datenum('2010-10-10')快 5 倍。

其次是使用 datenum 和 datestr 的替代函数,比如 datenummx 和 datestrmx。虽然在 Matlab 的正式文档中找不到 datenummx 和 datevecmx ,它们是真实存在的,并且是 MEX 格式,速度超快,实现从向量型日期到序列值的转换,其原型如下:

number = datenummx(year, month, day, hour, minute, second)
[year, month, day, hour, minute, second] = datevecmx(number)

在日期序列值和字符串表示的转换可直接通过 sscanf 和 sprintf 实现,这两个函数的性能都还不错。

如果嫌麻烦的话, Matlab file exchange 上有现成的已经封装好的函数可以用,比如DateConvert。我自个也封装了一个,分别为 mdatenum, mdatestr 分别用来代替 datenum 和 datestr :

[download name="datetime.zip"]

性能(可与上面直接的比较):

>> tic; for i = 1:10000, a = mdatenum('2010-10-30'); end; toc
Elapsed time is 0.259976 seconds.
>> tic; for i = 1:10000, a = mdatestr(734421); end; toc
Elapsed time is 0.364543 seconds.

当然如果你追求极致的话,还有另一个选择,用 C 写一个,编辑为 MEX 文件来调用。同样,已经有别人写好了,见DateStr2Num,按照其宣称的速度,将比上面的 datenummx、mdatenum 再快 5 倍。

Q. E. D.

类似文章:
上次说起遇到两个 Matlab 的效率问题,还剩下 save , load 没说。不过这个问题的结论挺简单的,就是在 save 的时候尽量指定使用-v6 选项。
没有人敢说 Matlab 的帮助文件不够详细和全面,但 Matlab 里面的确存在一些功能和函数,你很难找到它的帮助文档。下面列举一些,以后碰到其它的也会放到这里来:
如果一个日期(或者时间),如果用字符串,比如"2010-10-04"的形式,各个系统都没有什么区别。在某些时候,将日期用数字表示,将大大增加对日期查找、比较的效率。而如果用数字来表示日期,在不同的系统之间差别就大了。
上次大规模使用 Matlab 还是本科的时候,当时还是 5.3 版,现在重新尝试它,已经是 7.8 ( R2009a ),而且 R2010b 版都已经发售。而这些版本引入的一个新玩意儿便是面向对象化编程( object-oriented programming , OOP )。
相似度: 0.111
最近写了一些 Matlab 程序,想起以前想过的一个东西,记录一下。
编程 » Excel, VBA
VBA 的 Date 类型比较奇怪。
编程 » Matlab
在写 Matlab 程序时,函数的命名方式让人头疼,很难保证刚写的一个函数名在很久以前被用过,成为隐藏的一颗炸弹。
本文结论:不要过度担心 Matlab 的传值调用的效率问题。
相似度: 0.079
编程 » Matlab
写了一个统计代码量的函数,函数已上传到 Matlab Central File Exchange下载地址,使用方法:
编程 » Excel
Excel 中可设置每个单元格显示数字和文本的格式:
[Mathematics-techniques-in-finance]
以下对并行计算的个人理解受到较多质疑,删除之。