我正在比较 numpy vs matlab 的性能,在一些情况下,我观察到numpy明显变慢(索引,对数组的简单操作,如绝对值,乘法,求和等)。让我们看看下面的示例,它以某种方式引人注目,涉及函数数字化(我打算用它来同步时间戳):
import numpy as np
import time
scale=np.arange(1,1e+6+1)
y=np.arange(1,1e+6+1,10)
t1=time.time()
ind=np.digitize(scale,y)
t2=time.time()
print 'Time passed is %2.2f seconds' %(t2-t1)
结果是:
时间过去了55.91秒
现在让我们使用等效函数 histc
尝试相同的示例 Matlabscale=[1:1e+6];
y=[1:10:1e+6];
tic
[N,bin]=histc(scale,y);
t=toc;
display(['Time passed is ',num2str(t), ' seconds'])
结果是:
时间过去了0.10237秒
快560倍!
当我学习使用C ++扩展Python时,我实现了自己的数字化版本(使用扩展库的boost库):
import analysis # my C++ module implementing digitize
t1=time.time()
ind2=analysis.digitize(scale,y)
t2=time.time()
print 'Time passed is %2.2f seconds' %(t2-t1)
np.all(ind==ind2) #ok
结果是:
时间过去是0.02秒
由于我的数字化版本假设输入都是单调的,所以有一些作弊行为,这可能解释了为什么它比Matlab更快。但是,对大小为1e + 6的数组进行排序需要0.16秒(使用numpy.sort),因此与Matlab函数更差(约为1.6倍) > histc
所以问题是:
我正在使用Fedora 16,我最近安装了ATLAS和LAPACK库(但性能发生了很大变化)。我是否应该重建numpy?我不确定我的numpy安装是否使用适当的库来获得最大速度,也许Matlab正在使用更好的库。
更新
基于到目前为止的答案,我想强调的是,如果某人,Matlab函数 histc 与 numpy.histogram 不等同 (在这种情况下和我一样)不关心直方图。我需要hisc的第二个输出,它是从输入值到提供的输入区的索引的映射。这样的输出由numpy函数 digitize 和 searchsorted 提供。正如其中一个答案所说, searchsorted 比 digitize 快得多。但是,searchsorted 仍然比Matlab慢2倍:
t1=time.time()
ind3=np.searchsorted(y,scale,"right")
t2=time.time()
print 'Time passed is %2.2f seconds' %(t2-t1)
np.all(ind==ind3) #ok
结果是
时间过去了0.21秒
现在问题是:
如果有一个等效函数 numpy.searchsorted ,那么 numpy.digitize 的含义是什么? <280>快
为什么Matlab函数 histc (它还提供 numpy.searchsorted 的输出)比快2倍 > numpy.searchsorted
答案 0 :(得分:19)
首先,让我们来看看为什么numpy.digitize
很慢。如果发现您的垃圾箱是单调的,则会调用其中一个函数,具体取决于垃圾箱是否不减少或不增加(此代码可在numpy git repo中的numpy/lib/src/_compiled_base.c
中找到):
static npy_intp
incr_slot_(double x, double *bins, npy_intp lbins)
{
npy_intp i;
for ( i = 0; i < lbins; i ++ ) {
if ( x < bins [i] ) {
return i;
}
}
return lbins;
}
static npy_intp
decr_slot_(double x, double * bins, npy_intp lbins)
{
npy_intp i;
for ( i = lbins - 1; i >= 0; i -- ) {
if (x < bins [i]) {
return i + 1;
}
}
return 0;
}
如您所见,它正在进行线性搜索。线性搜索比二进制搜索慢很多,所以你可以回答为什么它很慢。我将在numpy跟踪器上打开a ticket。
其次,我认为Matlab实际上比你的C ++代码慢,因为Matlab also assumes这些分箱是单调非减少的。
答案 1 :(得分:5)
我无法回答为什么numpy.digitize()
这么慢 - 我可以在我的机器上确认你的时间。
函数numpy.searchsorted()
与numpy.digitize()
基本相同,但效率很高。
ind = np.searchsorted(y, scale, "right")
在我的机器上花费大约0.15秒,并且提供与您的代码完全相同的结果。
请注意,您的Matlab代码与这两个函数有所不同 - 它相当于numpy.histogram()
。
答案 2 :(得分:2)
在问题得到解答之前,需要解决几个问题:
为了获得更可靠的结果,您应该运行几个 迭代测试并平均他们的结果。这个会 以某种方式消除了启动效果,这些都没有任何关系 用算法。此外,尝试使用更大的数据 目的。
在框架中使用相同的algortihms。这已经是 在这里的其他答案中已经解决了。
确保算法非常相似。他们是怎么做的 利用系统资源?如何迭代内存?如果(只是一个 例子)Matlab算法使用repmat而numpy不会, 比较不公平。
相应的框架如何并行化?这可能 已连接到您的个人计算机/处理器配置。 Matlab确实并行化了一些(但不是全部)内置函数。 我不知道numpy / CPython。
使用内存分析器以了解两种实现方式 从表现的角度来看。
之后(这只是猜测)我们可能会发现,numpy通常表现得比Matlab慢。 SO的许多问题得出了同样的结论。一种解释是,Matlab可以更轻松地优化数组访问,因为它不需要考虑整个通用对象集合(如CPython)。对数学数组的要求远低于一般数组。另一方面,numpy确实利用了CPython,它必须服务于整个python库 - 不仅仅是numpy。然而,根据这个comparison test(以及许多其他人),Matlab仍然很慢......
答案 3 :(得分:1)
我不认为你在numpy和matlab中比较相同的函数。从我查看文档中可以看出,相当于histc
是np.histogram
。我没有matlab进行比较,但是当我在我的机器上执行以下操作时:
In [7]: import numpy as np
In [8]: scale=np.arange(1,1e+6+1)
In [9]: y=np.arange(1,1e+6+1,10)
In [10]: %timeit np.histogram(scale,y)
10 loops, best of 3: 135 ms per loop
我得到的数字大约相当于histc
的数字。