我在Python中编写了以下代码,以便估算Pi
的值。它被称为Monte Carlo方法。显然,通过增加样本数量,代码变得更慢,我认为代码中最慢的部分是在采样部分。
我怎样才能让它更快?
from __future__ import division
import numpy as np
a = 1
n = 1000000
s1 = np.random.uniform(0,a,n)
s2 = np.random.uniform(0,a,n)
ii=0
jj=0
for item in range(n):
if ((s1[item])**2 + (s2[item])**2) < 1:
ii = ii + 1
print float(ii*4/(n))
您是否建议其他(可能更快)代码?
答案 0 :(得分:8)
这里的瓶颈实际上是你的for
循环。 Python for item in range(n):
if ((s1[item])**2 + (s2[item])**2) < 1:
ii = ii + 1
循环相对较慢,因此如果需要迭代超过一百万个项目,则可以通过完全避免它们来获得大量速度。在这种情况下,它很容易。而不是:
ii = ((s1 ** 2 + s2 ** 2) < 1).sum()
这样做:
numpy
这是有效的,因为c
内置了对优化数组操作的支持。循环发生在>>> def estimate_pi_loop(x, y):
... total = 0
... for i in xrange(len(x)):
... if x[i] ** 2 + y[i] ** 2 < 1:
... total += 1
... return total * 4.0 / len(x)
...
>>> def estimate_pi_numpy(x, y):
... return ((x ** 2 + y ** 2) < 1).sum()
...
>>> %timeit estimate_pi_loop(x, y)
1 loops, best of 3: 3.33 s per loop
>>> %timeit estimate_pi_numpy(x, y)
100 loops, best of 3: 10.4 ms per loop
而不是python中,所以它的速度要快得多。我做了一个快速测试,所以你可以看到差异:
>>> a = numpy.arange(5)
>>> a ** 2
array([ 0, 1, 4, 9, 16])
以下是一些可能的操作示例,以便您了解其工作原理。
平方阵列:
>>> a + a
array([0, 2, 4, 6, 8])
添加数组:
>>> a > 2
array([False, False, False, True, True], dtype=bool)
比较数组:
>>> (a > 2).sum()
2
求和布尔值:
var object = { "eid": "12345666c85f0beaad3c52947bb2dd88" };
$.cookie("blah", JSON.serialize(object));
$.parseJSON($.cookie("blah"))
正如您可能已经意识到的,有更快的方法来估计Pi,但我承认我总是钦佩这种方法的简单性和有效性。
答案 1 :(得分:2)
您已经分配了numpy数组,因此您应该使用这些数据。
for item in range(n):
if ((s1[item])**2 + (s2[item])**2) < 1:
ii = ii + 1
变为
s1sqr = s1*s1
s2sqr = s2*s2
s_sum = s1sqr + s2sqr
s_sum_bool = s_sum < 1
ii = s_sum_bool.sum()
print float(ii*4/(n))
你正在对数组进行平方,对它们求和,检查总和是否小于1,然后将布尔值(false = 0,true = 1)相加,得到满足条件的总数。
答案 2 :(得分:1)
我赞成senderle
的答案,但如果您不想更改代码:
numba是为此目的而设计的图书馆。
只需将算法定义为函数,然后添加@jit
装饰器:
from __future__ import division
import numpy as np
from numba import jit
a = 1
n = 1000000
s1 = np.random.uniform(0,a,n)
s2 = np.random.uniform(0,a,n)
@jit
def estimate_pi(s1, s2):
ii = 0
for item in range(n):
if ((s1[item])**2 + (s2[item])**2) < 1:
ii = ii + 1
return float(ii*4/(n))
print estimate_pi(s1, s2)
在我的笔记本电脑上,n = 100000000
的加速比增加了约20倍,n = 1000000
的加速比增加了3倍。