Python 在Numpy中创建cos和sin数组的最有效方法

Python 在Numpy中创建cos和sin数组的最有效方法,python,arrays,numpy,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])

我需要存储一个大小为
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

有没有一种更短或更有效的方法来实现这一点?

您可以使用列表理解来缩短代码:

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矢量化

所以要回答你的问题:

有较短的路吗

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

有没有更有效的方法(我相信你的意思是“高效”)呢

我相信在不使代码过于复杂的情况下,这个问题的答案是否定的,因为numpy已经优化了矢量化(将cos和sin值分配给数组)

时机 比较各种方法:

OP's
randvector
:0.002131 s

My
randvector
:0.013218秒

mskimm的randvector:0.003175秒


因此,看起来mskimm的
randvector
在代码长度结束效率=D方面看起来不错

您的代码足够有效。我认为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's

      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}
      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}
4.707秒内调用5次函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1    0.001    0.001    4.707    4.707 :1()
1 2.452 2.452 4.706 4.706测试。py:6(随机向量1)
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
1 0.010 0.010 0.010 0.010{“mtrand.RandomState”对象的“随机样本”方法}
1 2.244 2.244 2.244 2.244{numpy.core.multiarray.array}
OP's

      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}
      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}
0.088秒内调用5次函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1    0.000    0.000    0.088    0.088 :1()
1 0.079 0.079 0.088 0.088测试。py:9(随机向量2)
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
1 0.009 0.009 0.009 0.009{“mtrand.RandomState”对象的方法“随机样本”}
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}
0.087秒内调用21个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1    0.000    0.000    0.087    0.087 :1()
2 0.000 0.000 0.000 0.000数值。py:322(asanyarray)
1 0.000 0.000 0.002 0.002形状_基础。py:177(vstack)
2 0.000 0.000 0.000 0.000 0.000形状\u底座。py:58(至少\u 2d)
1 0.076 0.076 0.087 0.087测试。py:17(随机向量3)
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{“列表”对象的“附加”方法}
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
1 0.009 0.009 0.009 0.009{“mtrand.RandomState”对象的方法“随机样本”}
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}

您的代码在我看来已经很好了,但这里还有一些想法

这是一条单行线。 它略慢于您的版本

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
1000 loops, best of 3: 366 µs per loop
如果您有权访问numexpr,则以下速度更快(至少在我的机器上)

这给了我时间:

1000 loops, best of 3: 698 µs per loop
1000 loops, best of 3: 366 µs per loop
老实说,如果我写这篇文章的目的不是为了提高性能,我会和你做的差不多。 这让读者很清楚你的意图。 带有hstack的版本也运行良好

另一个简要说明: 当我运行n=10的计时时,我的单行版本是最快的。
当我不使用n=10000000时,快速纯numpy版本最快。

请假设numpy作为
np导入,您的代码是有效的。更短的是@justhalf的答案,更短的是它的lambda版本。虽然这是有效的Python,但它实际上没有利用NumPy的矢量化。这将是相当慢的,因为您正在将涉及的for循环从C(如OP的解决方案)移动到Python。+1@IanH:是的,我正在进行计时实验,它确实慢了。我会尝试更多的实验。你们认为把问题从“更短或最有效…”改为“最有效”更好吗?要避免答案中包含两个答案?在您的解决方案中,“更短”的代价太高。正如所指出的,答案是缓慢的。此外,一行太长,这使得它难看和难以阅读,而OP的解决方案非常清楚。也许时间度量可以帮助决定哪一行:P(感谢vstack的介绍)我可以在我的答案中包括你的时间安排吗?