为什么数字化示例中的numpy比matlab慢得多?

我在比较numpy与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的相同示例Matlab

scale=[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函数histc相比,我的函数性能更差(约1.6倍)。

所以问题是:

  • 为什么numpy.digitize这么慢? 这个函数不应该写在编译和优化的代码中吗?
  • 为什么我自己的数字化版本比numpy.digitize快得多,但仍然比Matlab慢(我相当有信心使用最快的算法,因为我假设输入已经排序)?
  • 我使用的是Fedora 16,最近我安装了ATLAS和LAPACK库(但性能发生了变化)。 我应该重建numpy吗? 我不确定我的numpy安装是否使用适当的库来获得最大速度,也许Matlab使用更好的库。

    更新

    根据迄今为止的答案,我想强调,如果有人(如本例中的我)不关心直方图,那么Matlab函数histc 不等于 numpy.histogram。 我需要hisc的第二个输出,它是从输入值到提供的输入分档的索引的映射。 这种输出由数字化和搜索排序的numpy函数提供。 正如其中一个答案所述,searchsorted比数字化要快得多。 但是,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.digitize有什么意义,如果有一个等效的功能numpy.searchsorted这是280倍的更快

  • 为什么Matlab函数histc(它也提供numpy.searchsorted的输出)比numpy.searchsorted 快2倍


  • 首先,我们来看看为什么numpy.digitize很慢。 如果你的bin被发现是单调的,那么这些函数中的一个被调用,取决于bin是不是非递增还是非递增(这个代码在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跟踪器上为此打开一张票。

    其次,我认为Matlab实际上比你的C ++代码慢,因为Matlab也假定箱是单调非递减的。


    我无法回答为什么numpy.digitize()太慢 - 我可以在我的机器上确认你的时间。

    该功能numpy.searchsorted()基本上做同样的事情numpy.digitize()但有效。

    ind = np.searchsorted(y, scale, "right")
    

    在我的机器上需要大约0.15秒钟,并得到与您的代码完全相同的结果。

    请注意,您的Matlab代码与这两种函数的功能完全不同 - 它相当于numpy.histogram()


    在问题得到解答之前,需要解决几个子问题:

  • 为了获得更可靠的结果,您应该运行多次测试并平均其结果。 这会以某种方式消除启动效应,这与算法没有任何关系。 此外,尝试使用更大的数据用于相同的目的。

  • 在框架中使用相同的algortihms。 这已在其他答案中解决。

  • 确保算法非常相似。 他们如何利用系统资源? 如何迭代内存? 如果(只是一个例子)Matlab算法使用repmat而numpy不会,比较不公平。

  • 相应的框架如何并行化? 这可能会连接到您的个人机器/处理器配置。 Matlab并行化了一些(但不是全部)内建函数。 我不知道numpy / CPython。

  • 使用内存分析器来了解这两种实现在性能上的表现。

  • 之后(这只是一个猜测),我们可能会发现,numpy的行为往往比Matlab慢。 这里的许多问题都得出了同样的结论。 一种解释是,Matlab可以更容易地优化数组访问,因为它不需要考虑整个通用对象集合(如CPython)。 对数学数组的要求远低于一般数组的要求。 另一方面,numpy确实利用了CPython,它必须服务于完整的Python库 - 不仅是numpy。 然而,根据这个比较测试(等等),Matlab仍然很慢...

    链接地址: http://www.djcxy.com/p/85697.html

    上一篇: Why is numpy much slower than matlab on a digitize example?

    下一篇: Why is numpy's einsum faster than numpy's built in functions?