如何提高估计 Pi 的性能 Python
How to increase the performance for estimating `Pi`in Python
为了估算Pi
的值,我在Python中写了下面的代码。它被称为 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))
您是否建议其他(可能更快)代码?
这里的瓶颈实际上是你的 for
循环。 Python for
循环相对较慢,因此如果您需要迭代超过一百万个项目,则可以通过完全避免它们来提高速度。在这种情况下,这很容易。而不是这个:
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
而不是 python,所以它要快得多。我做了一个快速测试,所以你可以看到不同之处:
>>> 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
这里有一些可能的操作类型示例,只是为了让您了解其工作原理。
对数组求平方:
>>> 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
正如您可能意识到的那样,有更快的方法来估计 Pi,但我承认我一直很欣赏这种方法的简单性和有效性。
您已经分配了 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)以获得符合条件的总数。
我赞成 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 倍。
为了估算Pi
的值,我在Python中写了下面的代码。它被称为 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))
您是否建议其他(可能更快)代码?
这里的瓶颈实际上是你的 for
循环。 Python for
循环相对较慢,因此如果您需要迭代超过一百万个项目,则可以通过完全避免它们来提高速度。在这种情况下,这很容易。而不是这个:
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
而不是 python,所以它要快得多。我做了一个快速测试,所以你可以看到不同之处:
>>> 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
这里有一些可能的操作类型示例,只是为了让您了解其工作原理。
对数组求平方:
>>> 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
正如您可能意识到的那样,有更快的方法来估计 Pi,但我承认我一直很欣赏这种方法的简单性和有效性。
您已经分配了 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)以获得符合条件的总数。
我赞成 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 倍。