在Numpy中创建一系列cos和sin的最有效方法

时间:2014-04-09 02:57:46

标签: python arrays numpy

我需要存储一个大小为n的数组,其值为cos(x)sin(x),让我们说

array[[cos(0.9), sin(0.9)],
      [cos(0.35),sin(0.35)],
      ...]

每对cos和sin的论证都是随机选择的。就我一直在改进的情况而言,我的代码是这样的:

def randvector():
""" Generates random direction for n junctions in the unitary circle """
    x = np.empty([n,2])
    theta = 2 * np.pi * np.random.random_sample((n))
    x[:,0] = np.cos(theta)
    x[:,1] = np.sin(theta)
    return x

是否有更短的方式或更有效的方法来实现这一目标?

3 个答案:

答案 0 :(得分:4)

您的代码足够有效。而且我认为justhalf的回答并不差。

为了有效和简短,这段代码怎么样?

def randvector(n):
    theta = 2 * np.pi * np.random.random_sample((n))
    return np.vstack((np.cos(theta), np.sin(theta))).T

<强>更新

附加cProfile结果。

<强> justhalf的

      5 function calls in 4.707 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.001    0.001    4.707    4.707 <string>:1(<module>)
     1    2.452    2.452    4.706    4.706 test.py:6(randvector1)
     1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
     1    0.010    0.010    0.010    0.010 {method 'random_sample' of 'mtrand.RandomState' objects}
     1    2.244    2.244    2.244    2.244 {numpy.core.multiarray.array}

<强> OP的

      5 function calls in 0.088 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.088    0.088 <string>:1(<module>)
     1    0.079    0.079    0.088    0.088 test.py:9(randvector2)
     1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
     1    0.009    0.009    0.009    0.009 {method 'random_sample' of 'mtrand.RandomState' objects}
     1    0.000    0.000    0.000    0.000 {numpy.core.multiarray.empty}

<强>雷

      21 function calls in 0.087 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.087    0.087 <string>:1(<module>)
     2    0.000    0.000    0.000    0.000 numeric.py:322(asanyarray)
     1    0.000    0.000    0.002    0.002 shape_base.py:177(vstack)
     2    0.000    0.000    0.000    0.000 shape_base.py:58(atleast_2d)
     1    0.076    0.076    0.087    0.087 test.py:17(randvector3)
     6    0.000    0.000    0.000    0.000 {len}
     1    0.000    0.000    0.000    0.000 {map}
     2    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
     1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
     1    0.009    0.009    0.009    0.009 {method 'random_sample' of 'mtrand.RandomState' objects}
     2    0.000    0.000    0.000    0.000 {numpy.core.multiarray.array}
     1    0.002    0.002    0.002    0.002 {numpy.core.multiarray.concatenate}

答案 1 :(得分:2)

你的代码对我来说已经很好了,但是还有一些想法。

这是一个单行。 它比你的版本略慢。

def randvector2(n):
    return np.exp((2.0j * np.pi) * np.random.rand(n, 1)).view(dtype=np.float64)

我得到这些时间为n = 10000

此致:

1000 loops, best of 3: 716 µs per loop

我的缩短版本:

1000 loops, best of 3: 834 µs per loop

现在如果速度是一个问题,你的方法真的非常好。 另一个答案显示了如何使用hstack。 这很好用。 这是另一个与你的版本略有不同的版本,速度稍快。

def randvector3(n):
    x = np.empty([n,2])
    theta = (2 * np.pi) * np.random.rand(n)
    np.cos(theta, out=x[:,0])
    np.sin(theta, out=x[:,1])
    return x

这给了我时间:

1000 loops, best of 3: 698 µs per loop

如果您可以访问numexpr,则以下内容更快(至少在我的机器上)。

import numexpr as ne
def randvector3(n):
    sample = np.random.rand(n, 1)
    c = 2.0j * np.pi
    return ne.evaluate('exp(c * sample)').view(dtype=np.float64)

这给了我时间:

1000 loops, best of 3: 366 µs per loop

老实说,如果我写这篇文章并不是那些性能不是很高的东西,我会做同样的事情。 它使你的意图对读者非常清楚。 带有hstack的版本也运行良好。

另一个快速说明: 当我运行n = 10的时间时,我的单行版本是最快的。 当我做n = 10000000时,快速纯粹的numpy版本是最快的。

答案 2 :(得分:-2)

您可以使用列表推导使代码更短一点:

def randvector(n):
    return np.array([(np.cos(theta), np.sin(theta)) for theta in 2*np.pi*np.random.random_sample(n)])

但是,正如IanH在评论中提到的那样,这个问题比较慢。事实上,通过我的实验,这个速度慢了5倍,因为它没有利用NumPy矢量化。

所以回答你的问题:

  

有更短的路吗?

是的,这是我在这个答案中给出的内容,虽然它只缩短了几个字符(但它节省了很多行!)

  

是否更有效(我相信你的意思是&#34;高效&#34;)方式?

我相信这个问题的答案,没有过度复杂的代码,是不行的,因为numpy已经优化了矢量化(将cos和sin值分配给数组)

时序

比较各种方法:

OP&#39; randvector:0.002131 s

我的randvector:0.013218 s

mskimm&#39; s randvector:0.003175 s

所以似乎mskimm的randvector在代码长度效率方面看起来很好= D