np.random.permutation,np.random.choice的时间表现

时间:2016-02-24 01:13:05

标签: python numpy random

相对于我的纯python图论库中的类似MATLAB代码,我遇到了时间性能非常差的函数,所以我试图在这个函数中分析一些操作。

我跟踪了以下结果

In [27]: timeit.timeit( 'permutation(138)[:4]', setup='from numpy.random import permutation', number=1000000)
Out[27]: 27.659916877746582

将其与MATLAB中的性能进行比较

>> tic; for i=1:1000000; randperm(138,4); end; toc
Elapsed time is 4.593305 seconds.

我可以将此更改为np.random.choice,而不是像我原先写的那样np.random.permutation,从而大大提高了效果。

In [42]: timeit.timeit( 'choice(138, 4)', setup='from numpy.random import choice', number=1000000)
Out[42]: 18.9618501663208

但它仍然没有接近matlab的性能。

在纯python中是否有另一种获取此行为的方法,时间性能接近MATLAB时间性能?

2 个答案:

答案 0 :(得分:3)

根据this solution显示如何使用基于argsort / argpartition的技巧模拟np.random.choice(..., replace=False)的行为,您可以重新创建MATLAB的randperm(138,4) ,即NumPy的np.random.choice(138,4, replace=False)np.argpartition为:

np.random.rand(138).argpartition(range(4))[:4]

np.argsort喜欢这样 -

np.random.rand(138).argsort()[:4]

让我们将这两个版本用于与MATLAB版本进行性能比较。

在MATLAB上 -

>> tic; for i=1:1000000; randperm(138,4); end; toc
Elapsed time is 1.058177 seconds.

使用np.argpartition -

在NumPy上
In [361]: timeit.timeit( 'np.random.rand(138).argpartition(range(4))[:4]', setup='import numpy as np', number=1000000)
Out[361]: 9.063489798831142

使用np.argsort -

在NumPy上
In [362]: timeit.timeit( 'np.random.rand(138).argsort()[:4]', setup='import numpy as np', number=1000000)
Out[362]: 5.74625801707225

最初建议使用NumPy -

In [363]: timeit.timeit( 'choice(138, 4)', setup='from numpy.random import choice', number=1000000)
Out[363]: 6.793723535243771

似乎可以使用np.argsort来提高边际绩效。

答案 1 :(得分:2)

这需要多长时间?我估计1-2秒。

def four():
    k = np.random.randint(138**4)
    a = k % 138
    b = k // 138 % 138
    c = k // 138**2 % 138
    d = k // 138**3 % 138
    return (a, b, c, d) if a != b and a != c and a != d and b != c and b != d and c != d else four()

更新1:首先我使用random.randrange,但np.random.randint使整个事情的速度提高了一倍。

更新2:由于NumPy的随机功能似乎要快得多,我试过这个,这是另一个因素〜1.33更快:

>>> def four():
        a = randint(138)
        b = randint(138)
        c = randint(138)
        d = randint(138)
        return (a, b, c, d) if a != b and a != c and a != d and b != c and b != d and c != d else four()

>>> import timeit
>>> from numpy.random import randint
>>> timeit.timeit(lambda: four(), number=1000000)
2.3742770821572776

这比原版快22倍:

>>> timeit.timeit('permutation(138)[:4]', setup='from numpy.random import permutation', number=1000000)
51.80568455893672

(字符串vs lambda没有明显区别)